Computed property isn't recomputed when array dependency is mutated - polymer

I'm using a computed property as the items for a dom-repeat.
<template is="dom-repeat" items="{{double(values)}}">
<span>{{item}}</span>
</template>
When its dependency values changes, the property isn't recomputed.
addValue: function() {
this.push('values', this.values.length+1);
this.async(this.addValue, 1000);
},
If, instead of mutating values, I set it to a new array, it does work:
this.set('values', this.values.concat(this.values.length+1))
Is this a bug or expected behavior?
Demo: http://plnkr.co/edit/SmAHKMHhSPWgmBhBBzAv?p=preview

I spoke with Scott Miles, a member of the team behind Polymer, and I got this back:
In order for the computed property to bind properly, you must use [[double(values.*)]].
The parameter passed to your double function will be an object with properties path, value, and base, just as in path observation.
path will refer to a path string that specifies if length or splices was updated in the array,
value will be the value of length or splices, and
base will refer to your array.
Example:
<template is="dom-repeat" items="[[double(values.*)]]">
<span>[[item]]</span>
</template>
<script>
...
double: function(e) {
return e.base.map(function(n) { return n*2; });
}
Docs: https://www.polymer-project.org/1.0/docs/devguide/properties.html#array-observation
Demo: http://plnkr.co/edit/Idrz5XvLn9SZ35iR8pGT?p=preview
A dom-repeat template expects to be working with a collection, and thus when you bind it to values directly, it knows to keep tabs on the items in values.
Computed properties do not have any such expectations, and so [[double(values)]] doesn't work in this case because it will only update when the values reference itself changes, not when the items in the array change. Using values.* lets Polymer know that it should update the computed property binding when the array's contents are mutated.
I wouldn't post this here in Scott's stead if not for
sjmiles: #vartan: otoh, if you could transcribe what you learned, it would help me, time is my least elastic resource

Related

How to take some data from an object?

I have to put data from json file to my reducer.
And after mapping this file I got an object which includes data that I need.
export const datas = data.properties.map(data => (<store key={Math.floor(Math.random()*1234)} author={data.value} comment={data.group} rate={data.type} />));
this is console log, I just need props from this
How to get just normall react-table, not an object which is not accepting by reducer state?
Or how to implement it to reducer state to get effect that I need?
I am sorry for stupid questions, I hope you will help me :)
The code which you posted takes an array of objects from a variable data.properties and maps them to an array of JSX elements created by the component store. Perhaps it is better readable with line breaks.
export const datas = data.properties.map(
data => (
<store
key={Math.floor(Math.random() * 1234)}
author={data.value}
comment={data.group}
rate={data.type}
/>
)
);
Your console.log of datas shows that array of React JSX element instances. In your array you have 5 objects which are each a JSX element ($$typeof: Symbol(react.element)) with type: "store" (the component type), the numeric key that you created for this element, and a props object which contains all of the props that you passed: author, comment, and rate (key is a special prop so it is not included here).
You are asking to just create an object with the props rather than creating a store element. We want to take the array data.properties and use the .map() method to map it to this props object.
The variable name that you use inside of your .map() callback can be anything, but as a best practice I recommend that you should not use the variable name data again. Reusing a name is called variable shadowing and it won't cause errors, but it can make your code very confusing. I will call it datum instead.
Here is the code that you want:
export const propsArray = data.properties.map(
datum => ({
key: Math.floor(Math.random() * 1234),
author: datum.value,
comment: datum.group,
rate: datum.type,
})
);

How to destructure a Json array object to use in my react component?

I have sent a http get request and have received an JSON object as follows:
How can I destructure the json array and convert it into an array in my react component?
Alright, do you have an array of objects. It's no big deal my friend, you extract it on both of this ways, choose the one that fits your needs.
1st way, extracting only elements:
const [element1, element2, element3, ...rest] = carpak;
This way you will extract the three first elements to the variables above and the rest of the array will be placed in the variable rest.
2nd way, extracting properties of the elements in array:
const [{
id: id1,
latitude: la1,
longitude: lo1,
...rest: rest1,
}, {
id: id2,
latitude: la2,
longitude: lo2,
...rest: rest2,
}] = carpak;
In this example we accessed the first and the second element's properties. But we didn't care about the rest of the array of elements. Note that we are using some alias for the variables because if we don't do so, the variables would be used twice and we would have a compilation problem.
3rd way, extracting elements and properties from array:
const [{
id,
latitude,
longitude,
...restProperties,
}, element2, ...restElements] = carpak;
Now we have accessed the first element's properties, the entire second element and the rest of the elements in the array. Now we don't need aliases because we are only using the variables once.
Hope any of these help you man. In addition I would like to recommend you the next two links:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
https://hacks.mozilla.org/2015/05/es6-in-depth-destructuring/

Immutable JS duplicate / copy List within Map

I have an Immutable Map like this
Immutable.fromJS({
sortingOnFields: false,
items: [],
selectedItems: [],
columnsConfigs: {
meta: {},
columns: {}
},
});
how do I copy the items List to selectedItems list.
This return state.set('selectedItems', state.get('items'));
doesn't do the job correctly as later if I do
props.listing.get('selectedItems').includes(Immutable.fromJS(item));
where Immutable.fromJS(item) is from the 'items' List, it returns false.
I tried this which works but looks a bit too much
return state.set('selectedItems', Immutable.fromJS(state.get('items').toJS()));
any ideas of a better solution?
The problem is with your test. You are successfully setting the same List at both keys. You're retrieving the value at items, which is a List, and you're setting that exact same List as the value at selectedItems.
Even though that is working, your test isn't doing its job. You wrote:
props.listing.get('selectedItems').includes(Immutable.fromJS(item));
That line says: Get the List at selectedItems. Now create a brand new Immutable object using the fromJS method. Does the List at selectedItems contain that new Immutable object? The answer is no, because you just created that item from scratch, so it is definitely not contained in the List at selectedItems.
If each item is a primitive value, you can just check like this:
props.listing.get('selectedItems').includes(item);
If each item is a object, then did you convert it to an Immutable object? If not, then you can pass in a reference to the item, as above. If you did convert it to an Immutable object, make sure you pass a reference to the correct Immutable equivalent to the includes method.

using Meteor to display a collection with headers not known beforehand

Showing a collection of static known fields is basic to Meteor
where known fixed document key field names are placed in an html template.
However if all the field names are to be found at the time the
data is inserted,then the basic Meteor rendering cannot be used.
Is there any way to publish all the fields which are found by
parsing the json tabulated data ?
Perhaps Houston is the answer ?
Basically you just need to return keys as values along with the actual values. For example:
{{#each kvp object}}
key: {{key}}
value: {{value}}
{{/each}}
With a helper:
Template.myTemplate.helpers(function(){
kvp: function(obj){
return Object.keys(obj).map(function(k) { return {key: k, value: obj[k] });
}
});
That assumes an object with no nesting.
Object.keys(obj) gives you an array of keys. The map function then loops over each of those keys. In the mapping function we build a new object from the key and value. The end result is an array of objects that can be looped over in Blaze.

ES6 Set does not serialize to array

I've noticed that the Set in ES2015 does not implement a simple toJSON function, such as serializing to an array. Below is the implementation I came up with that does just that:
Object.defineProperty(Set.prototype, 'toJSON', {
enumerable: false,
value: function () {
return [...this];
}
});
Is there any reason why a Set does not serialize to an array?
Are there any edge cases where this override for toJSON is a bad idea?
See this answer as to why there can't be a general toJSON case for Maps, and for similar reasons, Sets. Basically, keys and/or Set items can be anything, including objects and references to other things that can't be serialized into JSON (which, remember, is a specific format with specific, stricter rules than just "turn into intelligible data of another type"). What you want here is more like "toArray" anyhow. You method already works for that inline, as would Array.from(Set), I think.
But if you wanted to add this sort of method to the prototype for your own internal usage without risking possible problems if a similar (but not identical) method is ever added, you could use a Symbol key'd prop.
var toArray = Symbol('toArray');
Object.defineProperty(Set.prototype, toArray, {
enumerable: false,
value: function () {
return [...this];
}
});
var g = new Set();
g.add(9);
g[toArray]();//-> [9]
If you do that, then you are guaranteed to not cause problems with anything other than your own code, since only your code will have access to the toArray Symbol key that references that method.