Clear an array in Polymer? - arrays

The polymer documentation says to always use the polymer array mutation functions when manipulating arrays. I do not see a function to clear an array. I see pop, push, shift, unshift and splice. For now i using this method:
<script>
Polymer({
is: "wc-example",
properties: {
data: { type: Array, value: function () { return [1, 2, 3]; } }
},
ready: function () {
this.data = [];
}
});
</script>
This works but it doesn't seem right because i'm not using the array mutation functions. Does anyone know the correct solution?
Thank you!

This perfectly ok. You are assigning a new instance to the property and this will be tracked by Polymer. Only manipulations on the same instance need to be done using the Polymer API. Note that you could use splice to clear an array.
this.splice("data", 0, this.data.length)

Related

Get some string values from an object Array and add those values into an observable

This is the obj array
workflows: ProteusWorkflow[]
ProteusWorkflow obj looks like this
export class ProteusWorkflow{
id: number;
workflowName :string
}
I need to add all the workflowNames from above Array to
filteredWorkflowsNew$: Observable<string[]>;
How can I do this? Please help me out!!
I've tried this...
this.workflows.forEach(w => {
this.filteredWorkflowsNew$.pipe(map(wfs=>{
wfs.push(w.workflowName);
return this.filteredWorkflowsNew$;
}));
});
but didn't work.
You can use the Array.prototype.map() operator.
map() function creates a new array populated with the results of
calling a provided function on every element in the calling array.
Please find more details about use of Array.prototype.map()
here.
let workflows = [{id:1,workflowName:"ABC"},{id:1,workflowName:"BDF"},{id:1,workflowName:"EWQ"}];
let filteredWorkflowsNew$=[];
filteredWorkflowsNew$ = workflows.map(obj => obj.workflowName);
console.log(filteredWorkflowsNew$) // ["ABC","BDF","EWQ"]

Async array without using anything async?

It drives me crazy. I have a really simple "problem" and it took me hours and still have no idea whats going on.
I have a child service which inherits from a parent service (I'm using ES6). The constructor takes an 1 argument called options. options will be assigned to this._defaults.
Now before I pass the options into my object (new Service(options)) I populate options with some data. To keep it simple, my current options object looks like this:
const options = {
types: []
}
Now I add some stuff into the types array, like this:
const Types = {
standard: {
some: 'data'
},
freeroll: {
some: 'data'
},
mainevent: {
some: 'data'
},
qualifier: {
some: 'data'
}
};
angular.forEach(Types, (val, key) => {
options.types[key] = true;
});
I assign my service to the scope like this:
$scope.service = new Service(options)
and output the service using console. The console now says the value of _defaults.types is Array(0). When I click on the array the correct values will be shown but the scope is not aware of that.
How is that? Doesn't Array(0) mean that at the time of the console.log() the array wasn't filled with any values but has been later? Like an async function would do?
Here is a plunk of my problem.
The problem is that types is an array and you're treating it like a plain Object. You can solve this one of two ways.
First just change types to an Object:
const options = {
types: {}
};
Or, if you need an Array, change how you're adding items to the array:
angular.forEach(Types, (val, key) => {
options.types.push({
type: key,
value: val
});
});
Note that this is just one way of turning the object into an array, the data structure you end up with is up to you.

Displaying data from Firebase in React without arrays

I am new to both React and Firebase. I struggled a bit to get data from the database, even though the instructions on the Firebase website were pretty straightforward.
I managed to print data in the view by using this code:
Get data from DB and save it in state:
INSTRUMENTS_DB.once('value').then(function(snapshot) {
this.state.instruments.push(snapshot.val());
this.setState({
instruments: this.state.instruments
});
From Firebase, I receive and Object containing several objects, which correspond to the differen instruments, like shown in the following snippet:
Object {
Object {
name: "Electric guitar",
image: "img/guitar.svg"
}
Object {
name: "Bass guitar",
image: "img/bass.svg"
}
// and so on..
}
Currently, I print data by populating an array like this:
var rows = [];
for (var obj in this.state.instruments[0]) {
rows.push(<Instrument name={this.state.instruments[0][obj].name}
image={this.state.instruments[0][obj].image}/>);
}
I feel like there's a better way to do it, can somedody give a hint? Thanks
I user firebase a lot and mu solution is little ES6 helper function
const toArray = function (firebaseObj) {
return Object.keys(firebaseObj).map((key)=> {
return Object.assign(firebaseObj[key], {key});
})
};
I also assign the firebase key to object key property, so later I can work with the keys.
The native map function only works for arrays, so using directly it on this object won't work.
What you can do instead is:
Call the map function on the keys of your object using Object.keys():
getInstrumentRows() {
const instruments = this.state.instruments;
Object.keys(instruments).map((key, index) => {
let instrument = instruments[key];
// You can now use instrument.name and instrument.image
return <Instrument name={instrument.name} image={instrument.image}/>
});
}
Alternatively, you can also import the lodash library and use its map method which would allow you to refactor the above code into:
getInstrumentRowsUsingLodash() {
const instruments = this.state.instruments;
_.map(instruments, (key, index) => {
let instrument = instruments[key];
// You can now use instrument.name and instrument.image
return <Instrument name={instrument.name} image={instrument.image}/>
});
}
Side note:
When you retrieve you data from Firebase you attempt to update the state directly with a call on this.state.instruments. The state in React should be treated as Immutable and should not be mutated with direct calls to it like push.
I would use map function:
_getInstrumentRows() {
const instruments = this.state.instruments[0];
if (instruments) {
return instruments.map((instrument) =>
<Instrument name={instrument.name}
image={instrument.image}/>);
}
}
In your render() method you just use {_getInstrumentRows()} wherever you need it.

React shouldComponentUpdate doesn't detect array length change?

When Changing the length of an array passed through props, the 'shouldComponentUpdate' function can't detect the array length change.
I know that 'shouldComponentUpdate' can't detect changes in nested objects properties, but this is a simple array length!! is this a bug in React??
https://jsfiddle.net/ashraffayad/cLz1q8sv/
var ArrTest = React.createClass({
render: function() {
return <div >{this.props.arr}< /div>;
},
shouldComponentUpdate: function(nextProps) {
console.log(this.props.arr.length, nextProps.arr.length); // same length !!!
return true;
}
});
// - - - - app component
var App = React.createClass({
getInitialState: function() {
return {
arr: [1, 2, 3, 4]
};
},
render: function() {
return <ArrTest arr={ this.state.arr } />;
},
componentDidMount: function() {
var self = this;
setTimeout(function() {
self.state.arr.push(7);
self.setState(self.state);
}, 2000);
}
});
ReactDOM.render( < App /> ,
document.getElementById('container')
);
It's not a bug in React, it's an issue with your code.
You should never modify this.state values directly.
Try this:
componentDidMount: function() {
var self = this;
setTimeout(function() {
self.setState({arr: self.state.arr.concat([7])});
}, 2000);
}
It works. Because React doesn't clone props as it passes them down, and so changes to an array get reflect on all of its references.
I suggest you read more about immutability in Javascript.
In short, never do this.state.[anything].push/pop/shift/unshift(), never.
Do something like this instead:
var arr = this.state.arr.slice(); // Create a copy of the array
arr.push(2); // do whatever you want to do
this.setState({ arr: arr }); // pass changes to React
Just because you have two references (this.props.arr, nextProps.arr) does not mean you have two instances.
When you mutate the array with push, you modify the instance. When shouldComponentUpdate runs it compares the references and because they point to the same instance, the array lengths are the same.
If you want to pass down a new array with different elements or properties, then you need to create a new array too.
It's quite easy to substitute push for concat.
setTimeout(function() {
self.setState({
arr: self.state.concat([7])
}, 2000);
You're referencing the same array in your if, ie., you are modifying the same array instead of creating a new one and you're working two references to the same array in shouldComponentUpdate.
You should always treat props and state as immutable and therefore creating a new array with .concat instead of pushing onto the array in state will fix your current issue.
setTimeout(function () {
this.setState({arr: this.state.concat([7])});
}.bind(this), 2000);
If you'd have done this.props.arr === nextProps.arr within shouldComponentUpdate you'd see that the arrays would be equal to each other.

Polymer 1.0 observers - not working on array

I set an observer on to catch all polymer recognized events on an property that is an array, but I catch get it to catch the change. In my example below my observer function "bigup" only gets called on when the property, "bigs" is first initialzed.
<dom-module id="parent-page">
<template>
<paper-button on-click="updateAll">Update</paper-button>
</template>
<script>
var temp=[];
temp.push({'conversation':[{'message':'hello'}]});
Polymer({
is: 'parent-page',
properties: {
bigs: {
type: Array,
value: temp
}
},
observers: [
'bigup(bigs.*)'
],
updateAll: function(){
this.bigs.push({'conversation':[{'message':'hola'}]});
console.dir(this.bigs);
},
bigup: function(){
console.log('big Up');
}
});
</script>
I also tried to use bigs.push in the observer but had no success. One part I don't understand is that if I add the following line to my "updateAll" function, the observer catches the change and fires "bigup".
this.bigs=[];
For me this article was helpful as well, it covers both the way to register the observer as well as the splices methods as suggested by Justin XL.
Registering the observer:
properties: {
users: {
type: Array,
value: function() {
return [];
}
}
},
observers: [
'usersAddedOrRemoved(users.splices)'
],
Calling splices methods the Polymer 1.0 way:
this.push('users', 'TestUser');
https://www.polymer-project.org/1.0/docs/devguide/properties.html#array-observation
FYI - this will NOT work in all cases (my initial idea)
When you register the observer in the property declaration like this:
properties: {
users: {
type: Array,
value: function() {
return [];
},
observer: 'usersAddedOrRemoved'
}
},
In this case the usersAddedOrRemoved method is only called when you assign a new array to the users object. It will not however fire when you mutate the array by pushing, popping, splicing etc.
You need to use the push method from Polymer instead of doing this.bigs.push.
So replace that line of code with
this.push('bigs', {'conversation':[{'message':'hola'}]});
For more info have a look at this link.

Resources