Vuejs2: How to re-render array computed properties when array changed - javascript

I have array named List and created computed property computedList for him.
When i update value of array it's not showing in html, but in console i see thar array is updated.
`https://jsfiddle.net/apokjqxx/69/`
What is best way to use computed properties for array?
Maybe is exists way to trigger to re-render computed property?

Due to limitations in JavaScript, Vue cannot detect the changes to an array like this: this.list[1] = 'vueman'
You have to use Vue.set or vm.$set as explained here to trigger state updates in the reactivity system, like follwoing:
this.$set(this.list, 1, 'vueman')
see updated fiddler here.

Related

Is it good practice to mutate Vuex with Vue.set with an object that is also an observable

Expected to achieve:
Most correct way to modify specific record stored in the Vuex state with one big (batch) write
Context:
Vuex state contains list of records with default values for each record.
Logic
Component initialises and uses getter to get one of the records.
It's needed to add new properties to the record and overwrite existing values.
Question
Is it acceptable to modify the object returned by the Vuex getter and later commit the whole result into the state? And if yes, what would be the best approach considering it will have to overwrite existing record in Vuex.
P.S: I also wonder if it can result in breaking behaviour of other components that are "getting" the same record that will be overwritten, and will appreciate a lot your thoughts on this topic :-)
Don't modify Vuex data except via Vuex mutation
1) First, clone the getter record. Make sure you deep clone if your record has anything but primitive properties, i.e it has properties that are objects or functions. Here are some cloning options, notice that many don't correctly deep clone.
2) Once you're done mutating the clone, call a Vuex action and have that action call a mutation. It's good practice to only call mutations from actions.
3) In that mutation, use Vue.set (or splice) to replace the state record.
4) Yes, if you mutated the getter directly, it would be mutated anywhere else it was used.
See Change detection caveats in the VueJS reactivity guide.
Sometimes you may want to assign a number of properties to an existing object, for example using Object.assign() or _.extend(). However, new properties added to the object will not trigger changes. In such cases, create a fresh object with properties from both the original object and the mixin object:
// instead of `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

Ember binding on custom objects

See twiddle here: https://ember-twiddle.com/2150099882893760cef237ff2bd22e85
Basically, in crit-service I create Ember Objects "Crits" and "Crit", and fill them with some data.
The crit-service is used by two different components, which basically do the same thing: display the Crits.
The problem is that the "change" buttons do not work. By debugging, I see that the values are changed, but the view is not updated. Why is this? Since Ember.Object is Observable, shouldn't setting a value notify the template? And most importantly, how can I get this to work?
P.S. I've seen a workaround by using Ember.A() instead of Objects. However, this would add boilerplate, as my data model is really objects and not arrays of key-value pairs.
This seems to be an issue with the {{#each-in}} helper which does not reload on changes. A quick fix is to use the {{get}} helper.
So instead of this:
{{#each-in obj as |key val|}}
{{key}}={{val}}
{{/each-in}}
Do this:
{{#each-in obj as |key|}}
{{key}}={{get obj key}}
{{/each-in}}
However, this will never work if you add additional properties.
here is a working twiddle with that solution.
Another solution that will always work is to call .rerender() on the component. This is save thanks to glimmer, which does only update the parts of the DOM that have changed. However, you would have to call it on your common root component of the two components, or on both components.

Differences on someArray.[] and someArray.#each

So I understand that Ember can compute on an array and elements within it. There are two options here.
someArray.[] and someArray.#each
If say I changed one of the element in array and there is a computed property that depends on it. Which one should I use? Thanks.
someArray.[] will only be used when the array items are added/removed.
When the particular property in the array object is changed then someArray.#each will be called.
isNameChanged: function() {
console.log('is Name Changed')
}.property('someArray.#each.name')
Can check this Ember.js: Observing array property using #each doesn't work

Ember.js: Using a computed property in handlebars from a Service

So I have this computed property inside my component.js: contexts: Ember.computed.oneWay('myService.contexts'),
And I am able to get the content from another action
openHelp(){
console.log(this.get('contexts'))
alert(this.get('contexts'))
}
}
But when I try to use the computed property in Handlebars ({{contexts}}) it's just blank.
I created an Ember Twiddle for this question: https://ember-twiddle.com/38de64d58dcf3298df6d4176f15cbc0e?openFiles=components.my-component-help.js%2Ctemplates.components.my-component-help.hbs
If I have an array foo: [ 'foo','bar'] and I do {{foo}} it outputs in handlebars. But if I make foo a computed property that gets [ 'foo','bar'] from and do {{foo}} I get nothing.
Here's the solution: https://ember-twiddle.com/e9c2ef05e27013a389e0b2bfdaec3d40?openFiles=services.my-service.js%2Ctemplates.components.my-component-help.hbs
There were two issues:
contexts is an array. When you console.log or alert it, those methods internally in some browsers JSON.stringify the object for you for your convenience. Ember will not do that. You need to format the array yourself or, as I did, each over it. For debugging purposes, feel free to use the log helper.
Computed properties on arrays are watching for array mutations through Ember's methods such as pushObject and removeObject. Simply using push or splice won't update the computed property.
Can't comment on the above answer which is correct because I don't have enough reputation, but I wanted to add a link to the documentation relating to Ember's observable methods for enumerables:
https://guides.emberjs.com/v2.5.0/object-model/enumerables/

react-redux: What is the difference between state.setIn() and state.set()?

I've seen the use of setIn() and set() in some react-redux code:
state.setIn(...);
state.set(...);
I've found some documentation here https://facebook.github.io/immutable-js/
But unfortunately the method is not documented in detail.
I also found some other questions: Using React's immutable helper with Immutable.js
But these do not answer my question.
I understand, that it must do some immutable stuff?
But what's the immutable thing here?
And what's the difference between set() and setIn()?
Why do we need immutable?
Immutable set method only sets immediate properties, I.e. direct children of the object. A setIn let's you set the value of any deep node down the data. set only takes property name. setIn takes an array of keys/index to reach down to the deeply nested element.
var basket = Immutable.Map({"milk":"yes", "flour":"no"});
basket = basket.set("flour", "yes");
basket = Immutable.Map({"fruits":{"oranges":"no"}, "flour":"no"});
basket = basket.setIn(["fruits", "oranges"], "yes");
The getIn/setIn methods are extremely useful when updating states in stores as you can use generic actions and supply the key paths to child components. They can invoke the actions passing the paths as parameters.
set and setIn are one of the immutablejs method which you use to set data in a list or map object. simple example to understand this is lets say you have a this
//note that fromJS is another method which comes from immutablejs library
const iniState = fromJS({
name:null,
friends:fromJS({
name:null
}),
})
in this case you need to update the initial state with the latest then that's where you can use set and setIn methods.
iniState.set('name',"sibusiso Massango").setIn(['friends','name'],"Zweli Mathebula");
this is how you can use the set and setIn method, to find more about this you can read this docs https://facebook.github.io/immutable-js/docs/

Categories