I have a pretty simple question about ember components.
I'm defining my model in my route:
model() {
return this.store.createRecord('player');
},
I'm passing the model to my component in my template:
{{region-picker model=model region="A" regionName=AName teamNameMap=teamNameMap}}
Then, inside my component, I can succesfully get the correct data from my model, but nothing that I change in my model is getting sent to the database. I can only assume this is because the model is being passed by value instead of by reference. Is there a way to pass it by reference, and if not, what is the common workaround for editing a model inside of a component.
Thanks!
the model should be updated, even if you change the data in the component.
Can you verify the same in the EmberJS plugin ? or did you make an explicit copy in the component.
The other thing you might be missing is you need to trigger model.save()
after your component has updated the model.
Related
I created this demo to explain better my goal: https://codepen.io/Albvadi/pen/OJMgByR
Each button create a new alert creating a object inside the vuex store in the components array. With the component property I know the type of the component to render.
Each alert generate a random string in a data property inside the component.
How do I need to configure the connection with Vuex to obtain the data from the child alert component inside the global components array?
Thanks!
Finally, I solved with a computed property that gives me the parent item. I don't know if it is the best way or if there is a simpler one, but I think it is the correct one.
computed: Vuex.mapState({
getParentItem(state) {
return state.components[state.components.indexOf(this.index)];
}
}),
Demo solved: https://codepen.io/Albvadi/pen/wvMrpLv
In Angular, if we want to bind a property from outside for a custom component, we have to use "#Input" to kind of allow that property to be set from outside (i.e. from consuming component template)
Does EmberJS also have some sort of similar mechanism OR does it allow binding directly from the template (hbs) without adding/marking anything in the component JS? Is there any difference when it comes to Ember Octane V/s the earlier versions of Ember?
yes it allows binding from outside the component without adding anything to the component js
in the component hbs file
<p>{{#attribute}}</p>
from outside
<MyComponent #attribute="attributeValue"/>
also you can get the binded attribute from component js
#tracked mycomponentAttribute = this.args.attribute;
in the component hbs file
<p>{{this.mycomponentAttribute}}</p>
no you don't necessarily have to add the input tag but you have to declare the property inside the component you are trying to pass the property to.
{{#each model as |post|}}
{{blog-post title=post.title body=post.body}}
{{/each}}
the blog-post component, define a property named title and this should work.
I wonder how does this line work:
this.ref.markForCheck();
Or:
this.ref.detach();
While ref is: ChangeDetectorRef
I didn't see a way to get in a service the component that called you, so how does angular knows which component called it when I call this.ref.detach(); and detach the right component?
I would expect a call like this.ref.detach(this); so I pass the reference to the component, but seems like angular service has a way to access the caller?
Added jsfiddle https://jsfiddle.net/1hk7knwq/11788/
Look at the test() call, somehow the ref service is also getting the component instance without me explicitly passing it.
Thanks
I am making an app just for practice and i have a doubt in a component's function "didReceiveAttr". When i pass my MODEL in my template and then i erase some element in it the function doesnt work, but if i pass "model.length" in the template and then erase something the function work!
My component template
<h1>Tasks ({{totalTask}})</h1>
My component JS
totalTask: null,
didReceiveAttrs(){
this._super(...arguments);
this.set('totalTask', this.get('model.length'));
console.log(this.get('model'));
}
My primary template
{{task-list model=model}}
or
{{task-list model=model.length}}
This is indeed the expected behavior; just look at Ember guide about how didReceiveAttrs works. It is clearly stated that "didReceiveAttrs hook is called every time a component's attributes are updated". When you add to or remove from an array the array itself does not change; hence didReceiveAttrs is not executed. It is only executed when the initial assignment to model is performed.
I prepared this twiddle to illustrate you a better ember way to handle this case. You should rely on computed properties as much as you can; hence I added computedTotalTask as a computed property to my-component.js and it relies on model.length as you can see.
{{task-list modelLength=model.length}}
Here you are assigningmodel.length as modelLength property to the component. so initially didReceiveAttrs will be called as component is receiving modelLength property and when you add one more element to model then modelLength property itself changed so this will invoke didReceiveAttrs before re-render.
{{task-list modelTaskList=model}}
Here modelTaskList is pointing to array, so when you add/remove item through KVO compliant method such as pushObject it will be reflected in component too. but the modelTaskList is still pointing to the same array so didReceiveAttrs hook will not be called.
Suppose if you assigned different array then you can see the didReceiveAttrs is called.
You could always just set this as a computed property, ensuring updates in the event of the bound variable being updated.
Within your component, set up a computed property that will watch for a change to your model, then update the variable modelLength with the change
modelLength: Ember.computed('model', function(){
return this.get('model').length;
}
Then, within your handlebars template, reference this length
<h1>Tasks{{#if modelLength}} ({{modelLength}}){{/if}}</h1>
All props form a one-way-down binding between the child property and
the parent one: when the parent property updates, it will flow down to
the child, but not the other way around. This prevents child
components from accidentally mutating the parent’s state, which can
make your app’s data flow harder to reason about. In addition, every
time the parent component is updated, all props in the child component
will be refreshed with the latest value. - One-Way Data Flow
The Vue2 Component Docs suggests doing the following to use props as an initial value:
// via https://v2.vuejs.org/v2/guide/components.html#One-Way-Data-Flow
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
So in my code I mimicked those instructions here.
However data() in Note.vue isn't being updated even though the prop value is received according to vue-devtools.
Haven't had success setting the values with the mounted or created lifescyle methods.
When I use static data, this seems to work fine, how can I ensure the child component reacts to receiving props when it comes from a remote source?
When you are passing initialNote as prop for initial value, but I see initialNote is being populated asynchronously in getNote method, so it will not be present initially when the component will be mounted. It will be populated after some time by the time initialisation would have already happened.
In the example give in vue documentation, initialCounter is static value which will perfect as it will have same value from beginning.