Vue object properties not changing with v-bind:class - javascript

I have a object which kind of looks like this:
{
data: [
{
id: 28,
type: "blabla",
name: "myname",
language: "en",
active: true
},
{
id: 5,
type: "blabla",
name: "myname2",
language: "fr",
active: false
},
// etc
]
}
I have split this object up into groups which I am display like this:
<li class="suggestion" v-for="suggestion in group">
</li>
I want to highlight my results so that is why I have a position property on my Vue object. which can be changed.
I have a watcher set up for the position attribute:
position() {
this.suggestions.forEach((suggestion, index) => {
suggestion.active = index === this.position;
});
}
It will make the current position(so the currently item active). This works fine when I am checking the array of objects and their properties. The items change their .active property perfectly. But the class binding does not seem to re-evaluate.
What is going wrong here? The initial active state does get taken into account and my first item is highlighted perfectly fine.
Nothing happens on a change to the actual classes though yet with the Vue devtools I can see perfectly fine that the objects properties are changing.

So the problem was that if object gets created like this:
object[suggestion.type].push(suggestion);
Vue doesn't detect changes to that object. It has to do with how Vue watches objects for changes.
In order for Vue to play nicely with objects you create and want to be reactive you need to utilize Vue.set
Vue.set(object, suggestion.type, suggestion)
Or
this.$set(object, suggestion.type, suggestion)

Related

Directly update mapbox source features

I'm drawing orders on the map using layers with symbols, this orders has status. Whenever the status changes I'd like to change de color of the symbol.
My layer has this configuration:
map.addLayer({
id: "orders",
type: "symbol",
source: "order-markers",
layout: {
"icon-image": [
"match",
["get", "orderStatus"],
"UNASSIGNED",
"unassigned-marker",
"ASSIGNED",
"assigned-marker",
"IN_TRANSIT",
"intransit-marker",
"CONCLUDED",
"concluded-marker",
"UNASSIGNED-marker",
],
},
});
});
Is there a recommended way to directly access the source and update the status in the properties object ? Or is it right to always overwrite the whole data object with setData ?
I tried to create a state in React with the features but it seems that the features object dont react to the state changes.
Thanks.
I haven't found a way to update a single property on a single feature. What I've always done is to overwrite the data as you've mentioned (i.e. map.getSource('order-markers').setData(/*...*/)) with the whole data object where a feature's property was changed. This is the method mapbox uses in their example for updating with live data: live-update-feature
As an alternative however, you can update a single feature's state. If that's a possibility you can use map.setFeatureState.
for example:
map.setFeatureState(
{
source: 'order-markers',
id: feature.id,
}, {
status: "IN_TRANSIT"
}
);
You'll then have to update your layer style/expressions to use the state instead of property to properly reflect the data as they are slightly different in how you get the values.

Vue reactivity issue, need some explanations

I've removed most useless parts of my code, so don't worry if this code doesn't really make sense, it's just to show you what's not working.
First, I create an array from a base array called objects:
objects: [
{
text: "I dont trigger stuff",
},
{
"text": "I dont trigger stuff",
},
{
text:"I trigger stuff",
activated: undefined,
},
],
And the create function
created() {
const newArray = [];
this.objects.forEach(anObj => {
anObj.activated = false;
newArray.push(anObj);
});
this.filteredObjects = newArray;
},
I initialize a property activated to false. In my real code I'm not using a forEach, but a find but the result is the same.
Then, I display a few buttons to trigger an "activation"
<button
v-for="(myObj, index) in filteredObjects"
:key="index"
#click="activateObject(myObj, index)">
{{ myObj.text }}
</button>
And the function being triggered is this one:
activateObject(anObj, anObjIndex) {
this.$set(this.filteredObjects[anObjIndex], 'activated', !anObj.activated)
},
My goal here is just to update the activated property.
To check if reactivity is working, I've got a watcher:
watch: {
filteredObjects: {
handler() {
alert('called')
},
deep: true,
}
},
I've got two questions:
1/ Since all activated properties are set to false for all objects, why is there only one working, the one with the property initially set to undefined?
2/ If I update my activation function to:
activateObject(anObj, anObjIndex) {
anObj.activated = !anObj.activated;
this.$set(this.filteredObjects, anObjIndex, anObj);
},
It works well. Can someone explain me why, and what is the difference?
In both cases, VueJS Devtools shows the updated values when clicking on refresh. It's a reactivity issue.
You can find a fiddle here:
https://jsfiddle.net/dv1jgneb/
From the Docs:
Since Vue performs the getter/setter conversion process during instance initialization, a property must be present in the data object in order for Vue to convert it and make it reactive.
This explains why only the third button "trigger stuff".
So, you may either add that attribute in the data(), or as said in the docs, use this.$set:
this.objects.forEach(anObj => {
this.$set(anObj, 'activated', false);
newArray.push(anObj);
});
JS Fiddle
Hope this helps!

Unable to observe an array of objects in Ember.js?

I have an array of objects within a component like this:
checkboxes: [
{
label: 'A',
state: false
},
{
label: 'B',
state: false
},
{
label: 'C',
state: false
}
]
In my Handlebars template, I have a loop to show the list of checkboxes and each checkbox state maps back to the array item like this:
{{#each checkboxes as |item|}}
<li><input type="checkbox" checked={{item.state}}> {{item.label}}</li>
{{/each}}
I wrote an observer to observe changes to the array but it doesn't seem to work:
observeCheckboxes: function() {
console.log(this.get('checkboxes').toArray());
}.observes('checkboxes.[]')
How do I observe changes to the checkbox states so I can get a list of checked items?
Change your observer to observe checkboxes.#each.state.
Have a look through the documentation here for a complete overview.
If possible, try to avoid using an observer, and rather use a computed property, and then also to rather define computed properties and observers as Ember.computed & Ember.observer.
Here is a twiddle that demonstrates why your observer is not firing.

Why isn't my view re-rendered again as expected?

I created a custom control which includes a currentValue property. I defined it in metadata as below:
properties:
{
currentValue:
{
type: 'int',
defaultValue: 0
},...
in my Main.controller.js I'm calling the custom control that I created and changed it's currentValue property as below.
var oCustomControl = this.getView().byId("customID1");
oCustomControl.setCurrentValue(75);
in this step in my control.js, I didn't create a setCurrentValue function. Because I know UI5 is creating it itself. But the currentValue property of my control couldn't been updated. So I'm thinking my control couldn't been rerendered. So I overwrote the currentValue setter and change it as below:
setCurrentValue : function(iCurrentValue)
{
this.setProperty("currentValue", iCurrentValue);
},
But still I couldn't see the value which I changed in my view.
Here is my renderer:
renderer :
{
render : function(oRm, oControl) {
var layout = oControl.createGauges();//I created layout
oRm.write("<div");
oRm.writeControlData(layout);
oRm.writeClasses();
oRm.write(">");
oRm.renderControl(layout);
oRm.addClass('verticalAlignment');
oRm.write("</div>");
}
},
I am thinking now maybe it is because I'm rendering layout as a control?
and my other properties are related with d3.js. And I coded d3.js codes in my onAfterRendering function.
Actually your code looks fine.
Accept that you have specified:
bindable: 'bindable'
What should that do?
And what does rerender()?
The method to render a control is called renderer().
But you don't need to call it when you say:
this.setProperty("currentValue", iCurrentValue);
If you dont say true it will rerender the control.
It would be nice to know whats inside your renderer() function, or what happens when you call getCurrentValue().
It is solved by changing
oRm.writeControlData(layout); this line as follow:
oRm.writeControlData(oControl);

Query for Rollups/Features filtering by Parent

I have a list of portfolio items that the user can click on, and when the user clicks on one, I want to query for the children of that item. I have the initiatives separate from the the rollups which are separate from the features, and when it is clicked, I am getting the correct data.
However, When I try to query for its children, I run into problems. Take the following example.
If a rollup was clicked on, I have tried these queries:
Rally.data.ModelFactory.getModel({
type: 'PortfolioItem/Feature',
success: function(model) {
Ext.create('Rally.data.WsapiDataStore', {
model : model,
limit : Infinity,
fetch : true,
// filters : [{
// property : 'Parent',
// operator : '=',
// value : rollup
// }]
}).load({
callback : function(store) {
console.log('got features');
console.log('first feature',store.getItems()[0]);
}
});
}
});
When I run the query with the filters commented out as shown, then I get all of the features. However, when I add in the filters, I get nothing back! I have tried setting the variable Rollup to the rollup's ObjectID/name, and still nothing. when I console log one of the features, I can see:
Parent: Object
_rallyAPIMajor: "2"
_rallyAPIMinor: "0"
_ref: "/portfolioitem/rollup/xxxxxxxx"
_refObjectName: "xxxxxxxxxxxxxxxxxxxxxxxx"
_type: "PortfolioItem/Rollup"
and that is it. Furthermore, I know there are portfolio items that meet the requirements I am trying to express in the filters. How can I filter out by parent when querying for portfolio items?
Well, I thought I had tried all possible combinations, but it appears that, even though it does not appear as a field when printed, the correct filter is:
filters : [{
property : 'Parent.ObjectID',
operator : '=',
value : rollup
}]

Categories