Reputation: 131
I need to generate a random string from two arrays with a bunch of names of people and devices. I have an Ember computed property that does it perfectly well. Except computed properties only happen once. So I end up with a list of like 5 rows with the SAME TEXT.
The reason I'm doing this is because I am getting a list of devices from a REST web service, but they don't have the ability to return the name of the device, only id and a bunch of other info. So I am supposed to use dummy names for now, and so I figure. no problem. I'll just generate a random name for each row. Well as I already said, I end up with this:
John's iPad <actual unique ID from the server>
John's iPad <actual unique ID from the server>
John's iPad <actual unique ID from the server>
John's iPad <actual unique ID from the server>
John's iPad <actual unique ID from the server>
When it needs to be the name of a random person and random device (which I have in arrays and the code works perfectly, but only executes once, and returns the same value for each consecutive time it's called.
So then I read on here and in an Ember book I have to do this:
property1: function() {
bunch of code
}.property('property2');
So this is supposed to run every time property2 changes, except. Back to square one. How do I change property2? I can't do it from the hbs template, from the code within the {{#each}}
.. Then I read somewhere to use a custom helper, but in my experience ANY helper ecapsulates the returned value in a div which breaks the layout and would result in
text
helper response
remaining text
when what I want is:
text helper response remaining text
I mean yeah I could just make an array of text and then pass the index but then when I add new data I have to manually add items to the array because it's not dynamically generated for every row of data.
With my method I have like a ton of names and device names chosen randomly so no matter how much data is returned it can populate the name field until they fix it on the back end to return names.
Would really love to know how not just to solve this problem but how to run ANY CODE that I want from ANY PLACE I want in the page/template/etc. not just static properties or computed once properties..
sometimes you want to be able to have templates that use variables in them that are completely dynamic ran EVERY TIME that component is called.
Sometimes you want an actual helper that doesn't encapsulate the response in a div, so you can do stuff like The answer is {{answer-helper}}.
and not have the output be this:
The answer is
5
.
Upvotes: 0
Views: 2438
Reputation: 18240
Okay, first there are helpers if you just won't to output data. And the helper does not encapsulate anything in a div. And a helper is not a component. A component usually produces a div
. But if you want a component that doesn't produce a div
you can just set tagName
to ''
.
And thats what you should do: use two components:
device-list/template.hbs
{{#each devices as |device|}}
{{device-data device=device}}
{{/each}}
device-item/template.hbs
{{myprop}}
device-item/component.js
import Ember from 'ember';
export default Ember.Component.extend({
tagName: '',
myprop: Ember.computed('device.foo', {
get() {
return this.get('device.foo') + 'bla';
}
}),
});
now you have the property myprop
once for every item in the array.
Another option is to have an array as computed property:
devicesWithNames: Ember.computed('[email protected]', {
get() {
return this.get('devices').map(device => ({
foo: device.foo,
name: device.foo + 'bla', // anything you want to do
}));
}
}),
Another way to solve your problem is an ArrayProxy
.
Would really love to know how not just to solve this problem but how to run ANY CODE that I want from ANY PLACE I want in the page/template/etc. not just static properties or computed once properties..
You can't, and thats good. This forces you to follow clean standards. For example you can't just call code on the component from the template. You can invoke helpers, or use data provided by the template. But this is a one-way data flow, and this helps a lot in understanding how a component works. If you need to do this use a computed property, and if you need this inside an {{#each}}
loop write another component to be used inside the loop.
sometimes you want to be able to have templates that use variables in them that are completely dynamic ran EVERY TIME that component is called.
It seems you don't understand this. But this works as expected. A component that is called twice will compute all properties twice. However you need to understand that if you use an {{#each}}
loop you are still in the same component, so where would you want to declare the property that should run for every instance in the array? Thats why you need another component for this. The other option is to have a computed property that does provide you with a new different array, with all the required data.
Upvotes: 1