emberjs getEach method does not work as expected - ember.js

I have the following code which I expect to return [1000] but returns [undefined]:
this.get('details').getEach('gross_total')
But
this.get('details')[0].get('gross_total')
does work and returns 1000.
I am using rc3 right now. The same code in rc1 worked fine.
My persistence layer is taken from discourse. The relevant models are below. Invoice has_many details
App.Invoice = App.Model.extend App.Commentable,
invoice_number: App.Attr('string')
description: App.Attr('string')
issue_date: App.Attr('date')
due_date: App.Attr('date')
contact: App.BelongsTo('App.Contact', "contacts")
details: App.HasMany('App.InvoiceDetail', "detail_ids")
payments: App.HasMany('App.Payment', "payment_ids")
invoice_status: App.Attr('string')
comments: App.HasMany('App.Comment', "comment_ids")
App.InvoiceDetail = App.Model.extend App.DestroyableChild,
detail_no: App.Attr('int')
description: App.Attr('string')
quantity: App.Attr('float')
unit_price: App.Attr('currency')
consumption_tax_rate: App.Attr('float')
vat_rate: App.Attr('float')
discount_type: App.Attr('string')
discount_value: App.Attr('currency')
product: App.BelongsTo('App.Product', 'products')

I have seen this issue when prototyping require.js use for loading my app. Using ember.js 1.0.0-rc.1.
I traced it down to having two ember.js script instances (each of which contains its own different Ember.META_KEY) which implied the illogical behavior.
So the answer seems to be to make sure only a single ember.js copy is loaded within the browser window context.

Related

Ember.js - Matching model data and has many relationship in controller

I'm trying to build a table component that displays all matching data. I don't know how to get this working.
I have multiple Platforms that have many Markets.
The model is easy:
model() {
return this.store.findAll('platform', {include: 'markets'});
}
I can display check boxes so the user can select what platforms to compare and access the id's in the controller.
How do I go about getting the correct records from the model in the controller? I can't do this in the route because it depends on what platforms are selected.
I can use Ember Data:
this.get('store').findRecord('platform', id, {include: 'markets'})
But I can't figure out how to access the markets.
I tried enumerables also, but the same issue:
this.get('model').filterBy('id', id)
After this, what is a clean way to get the matching markets based on their name?
For your situation, you can access and compare the markets based on any selected platforms within your component. Each platform should have a relationship established to its associated markets within the model file. The relationship will allow you to access the markets off of the platform. For example, platform.get('markets') within a controller, component or {{platform.markets}} within a template. For a bit more detail on the rough process for implementing throughout the app files:
//Within the platform.js model just to set the basic relationship
markets: hasMany(),
//Within your controller.js build an array of selected platforms
selectedPlatforms: null,
actions: {
selectPlatform(platform) {
this.get('selectedPlatforms').pushObject(platform);
},
}
//Within your template.hbs provide your component the array
{{matching-markets platforms=selectedPlatforms}}
//Within your component.js compare the platform markets
platforms: null,
matchingMarkets: computed('platforms', function() {
const platform1Markets = this.get('platforms.firstObject.markets');
const platform2Markets = this.get('platforms.lastObject.markets');
return /* Compare platform1Markets against platform2Markets */;
}),
// Within the component.hbs
{{#each matchingMarkets as |market|}}
{{market.name}}
{{/each}}
Please reference the below link to an EmberTwiddle to see a rough (slightly hacky) example that might provide some better insight:
https://ember-twiddle.com/364d9c04d37593f4a7c40cccf065a8fc?openFiles=routes.application.js%2C

Embedded has many relationship not always working

I have a ticket model that has a property for ticket_holders that is a hasMany relationship
ticket_holders: DS.hasMany('ticket-holder'),
The ticket-holder model has a ticket property defined as a belongsTo
ticket: DS.belongsTo('ticket')
In the ticket serializer I defined the EmbeddedRecordsMixin and set the attrs property like so
export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin,{
attrs: {
ticket_holders: {embedded: 'always'}
},
...
An example ticket from the API looks like this
{
"eid":"5060",
"user_id":"13193",
"ticket_id":"612",
"ticket_purchase_code":"1ab9e0f20178220a75d5d2ca18322efa",
"ticket_purchase_behalf_name":null,
"ticket_purchase_behalf_email":null,
"ticket_name_alias":null,
"ticket_cost":"0.00",
"ticket_ticketing_time":"2015-11-17 11:24:32",
"ticket_qty":"1",
"ticket_total":"1.00",
"ticket_paid":"1",
"ticket_transaction_id":"noch_5060564b54c0c42ffy0M8tpk",
"ticket_validation_phrase":"",
"ticket_pay_type":"card",
"ticket_qty_redeemed":"0",
"ticket_refunded":"0",
"ticket_promo_code_used":"",
"ticket_name":"Ticket #2",
"ticket_purchase_user_name":"Tony Stark",
"ticket_holders":[
{
"holder_code":"hc_299dc35e",
"holder_user_id":"0",
"holder_id":"8181",
"holder_name":"Jordan again",
"holder_email":"Riser.jordan#gmail.com",
"holder_phone":"",
"holder_paddle_number":"4888",
"holder_rsvp":"0",
"holder_redeemed":"1",
"holder_last_updated":"2016-05-13 19:07:13",
"ticket_qrcode":"barcode\/barcode.processor.php?encode=QRCODE&bdata=&qrdata_type=link&qr_link_link=http%3A%2F%2Fbidr.co%2Fl%2F8qexEa&height=500&scale=2&bgcolor=%23ffffff&color=%231B3448&file=&folder&type=png&Genrate=Create+Barcode&ECLevel=L&margin=",
"ticket_pdf":"http:\/\/bidr.co\/ticket\/pdf_ticket.php?s1=1ab9e0f20178220a75d5d2ca18322efa&s2=hc_299dc35e"
},
...
]
}
The primaryKey for a ticket is set to primaryKey: 'ticket_purchase_code', so in the normalize function for the store method I'm using I loop over each ticket grab it's ticket_purchase_code and then loop over each ticket's ticket_holders array and set a new property on each called ticket_purchase_code to the one I got from it's parent ticket record.
It seems that ticket-holder's are not always being attributed to the ticket when I attempt to loop over the ticket and then it's ticket_holders in the template
{{#each tickets as |purchase|}}
...
{{#each purchase.ticket_holders as |ticket|}}
...
{{/each>
{{/each}}
Sometimes I only see one ticket-holder under each ticket sometimes I see all the correct ticket-holder's under each ticket, but more consistently I'm only seeing one ticket-holder under each ticket
Do I have my relationships set up wrong?
I have also tried changing the ticket_purchase_code on each ticket_holder that I loop over in the ticket serializer to ticket_id to see if that would work but it's not working correctly either.
I've run into this before myself Jordan. For me the situation was that I had 2 tickets that both had the same ticket-holder, i.e., "ticket_id":"612" and "ticket_id":"633" both have "holder_id":"8181". By the nature of a belongsTo poor "holder_id":"8181" can only be linked to a single ticket, so only the last ticket to load into ember-data that has "holder_id":"8181" will get to keep him.
The Solution
Trying commenting out DS.belongsTo('ticket') in ticket-holder, and see if they all load in like you'd expect.
// Try commenting the ling below out
ticket: DS.belongsTo('ticket')
Example, in this http://jsbin.com/sevipa/1/edit?html,js,output ,
App.Contact = DS.Model.extend({
name : DS.attr('string'),
// Turn the below on to see your problem. Matt H belongsTo 2 different companies
//company : DS.belongsTo('Company')
});
I commented out the relationship to company : DS.belongsTo('Company') so that Matt H will show up in both the first 2 companies. If you put the line back in, you will see that he only continues to belongTo Johns Shoe Repair since it loads into ember-data after Housing4Hope.

Ember Data Nested Resources Tree Structure

I have a slightly peculiar problem with loading my tree structure into Ember.
My models are:
book.js
- parts: DS.hasMany('part', {inverse: 'book', async: true})
part.js
- subparts: DS.hasMany('part', {inverse: 'parent_part', async: true}),
With the following API responses:
GET /api/books:
{
books: [
{id: 1, links: {parts: "/api/books/1/parts"}},
...
]
}
GET /api/books/1/parts:
{
parts: [
{
id: 1,
subparts: [10, 11]
},
{
id: 2,
subparts: []
}
]
}
The problem is in the tree nature of the parts: The book only has direct descendants id 1 and 2, but these have sub-parts on their own.
The structure as it is works but results in multiple sub-queries for each part that was not included in the /books/1/parts result. I want to avoid these queries, not only because of performance reasons but also because I will need additional query parameters which would get lost at this step... I know about coalesceFindRequests but it introduces new problems.
To rephrase the problem, Ember Data thinks that every part that is included in the /books/1/parts response should be added directly to the book:parts property. How can I still load all records of the parts tree at the same time?
I tried renaming the fields, but Ember Data assigns the records based on the model name, not the field name.
I fear that some creative adapter overriding will be necessary here. Any idea appreciated. The backend is completely under my control, so I could change things on that end, too.
You need to use a process called sideloading, which should work as you expect (I've had issues in the past with sideloading data). As mentioned in this issue, you want to split your parts into two separate arrays.
{
// These are the direct children
"parts": [{...}, {...}],
// These are the extra records
"_parts": [{...}, {...}]
}

Where to put code from another JS library in Ember: controller, model, adapter, service?

Wrapping another javascript library to use with Ember bindings, etc, seems like an ordinary thing to do, but I haven't found much discussion of it.
I want to filter an ember record array using distance and travel time from the Google Maps Distance Matrix
service. I'm just not sure where in the application to encapsulate Google's javascript. Note: this is not a question about embedding a google map, it's about getting data into ember that doesn't come from a rest/json or fixtures as in all the tutorials and examples I've found.
Would people typically do this in the controller or create new models/adapters to get benefits from store caching? Or is there another way?
update: in case that's too vague, consider this: 20 records (with a google map component etc) listed by an array controller, a text field where the user types in a home address, a couple of other inputs where they set a maximum time or distance, and a search button which filters the listed records by comparing the user requirements with the result of querying the distance matrix for the home address to the 20 records' addresses, only showing the ones close enough to their home.
Use of the service in an application that doesn't display a Google map is prohibited.
So,the question is really about integrating a Google map to an Ember app.
Without any doubt you'll have to add the Google JS like in any other HTML project with:
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=MYSECRETKEY"></script>
So, the API is in global space and you just use it whenever you need it. Mostly all that will happen in your views, so you could wrap everything in a component. (I'm assuming that all relevant data has been passed from the controller to the view, it all depends on the design of your app.)
The following works, but it seems like it should be in the model/store/adapter layer.
App.DistanceController = Ember.Controller.extend
origin: (->
data = #get('data')
data.origin if data
).property('data')
destinationDistances: (->
data = #get('data')
data.distances if data
).property('data')
data: ((key, value)->
if arguments.length > 1
value
else
_this = this
value = null
service = new google.maps.DistanceMatrixService()
service.getDistanceMatrix(
origins: ["London, England"],
destinations: [
"Bristol, England",
"Edinburgh, Scotland",
"Leeds, England",
"Liverpool, England",
"Manchester, England",
"Newcastle, England",
"Nottingham, England",
"York, England"
],
travelMode: google.maps.TravelMode.DRIVING,
avoidHighways: false,
avoidTolls: false
, (response, status) ->
if (status == google.maps.DistanceMatrixStatus.OK)
distances = []
for destination, n in response.destinationAddresses
distances.push {
destination: destination
distance: response.rows[0].elements[n].distance.text
}
_this.set('data', {
origin: response.originAddresses[0]
distances: distances
})
)
value
).property()
kudos #rlivsey https://stackoverflow.com/a/20623551/395180

Using jsPlumb in an Ember.js Application

I am trying to learn how to use jsPlumb in my Ember.js application so I put a minimal jsFiddle together to demonstrate how they could work together.
In this example so far I just insert the nodes and add them to jsPlumb. I have not added any links between them yet. At this stage the nodes should be draggable but they are not.
Error I get in the browser console:
TypeError: myOffset is null
Which points to this part of the code in jsPlumb:
for (var i = 0; i < inputs.length; i++) {
var _el = _getElementObject(inputs[i]), id = _getId(_el);
p.source = _el;
_updateOffset({ elId : id });
var e = _newEndpoint(p);
_addToList(endpointsByElement, id, e);
var myOffset = offsets[id], myWH = sizes[id];
var anchorLoc = e.anchor.compute( { xy : [ myOffset.left, myOffset.top ], wh : myWH, element : e });
e.paint({ anchorLoc : anchorLoc });
results.push(e);
}
You can see that a simple example without integration with Ember.js works as expected. I know that this version of jsPlumb I have uses jquery-ui to clone elements and support drag and drop. A post here shows there is an issue with jquery-ui draggable functionality in Ember. However, I am not sure if I am hitting the same problem. If that is the same issue I am having, I would appreciate some help in how to implement the solution suggested there in my application. I am new to both Ember and jsPlumb, so I would appreciate clear guidance about what is going on here and what path to take.
How can I make this example work?
Luckily my suspicion was wrong and the issue was not with metamorph. jsPlumb and Ember work just fine together, without any hacks. I put a little example in this jsFiddle that demonstrates how they could work together.
Credit goes to Simon Porritt who helped me at jsPlumb user group to identify the problem. What I was missing was a simple call to jsPlumb.draggable element. However, the above error persisted after this fix.
The particular error message above was result of Ember calling didInsertElement an extra time with an element which did not make it to the DOM. I have reported this issue. One workaround is to check the element makes it into the DOM before calling jsPlumb. As you can see in the jsFiddle I have added this code in the didInsertElement hook to get rid of the error.
elementId = this.get 'elementId'
element = $("#"+elementId)
if element.size() > 0
console.log "added element", element
jsPlumb.addEndpoint element, endpoint
jsPlumb.draggable element
else
console.log "bad element"
Hope this helps someone.