I am using Ajax to populate data properties for several objects. As such, the properties I want to bind to do not exist at the time of binding.
eg:
<template>
<my-list v-bind:dataid="myobject ? myobject.data_id : 0"></my-list>
</template>
<script>
export default {
data () {
return {
myobject: {}
}
}
</script>
In the Vue docs https://012.vuejs.org/guide/best-practices.html it mentions to initialize data instead of using a empty object.
However I am using multiple Ajax created objects with tens of parameters and sub parameters. To initialize every sub-parameter on all objects like this:
myobject: { subp1: [], subp2: [] ...}
where myobject may be an object containing array of objects, or an array of objects containing sub-arrays of objects for example.
would take quite a bit of work. Is there a better alternative when binding to 'not-yet existing' objects?
First of all, an empty array is still "truthy", so your check here
v-bind:dataid="myobject ? myobject.data_id : 0"
always returns true. You should check for myobject.length instead. Your code should work now.
Also, you really don't need to define dummy objects for an array. Vue detects whenever you mutate an array.
https://v2.vuejs.org/v2/guide/list.html#Array-Change-Detection
Related
I'm struggling to understand how to dynamically create & populate a key: value pairs in an object in my state using Vue/Vuex, here's an example:
dataObject: {} (in state), and a mutation that creates the new key:value pairs:
setdataObjectProps: (state, payload) => {
for (let [key, value] of Object.entries(
state.dataObject
)) {
if (key == payload[0]) {
dataObject.total_operation_time = payload[1];
dataObject.machine_name = payload[2];
}
}
},
This solution works, but the key:value pairs should already be existing in the object (i've set them to empty strings).
I tried using Vue.set() like this:
Vue.set(dataObject.total_operation_time, payload[1]);
Vue.set(dataObject.machine_name, payload[2]);
However, i'm struggling to understand how to make it work since it expects second parameter that's the index/name, if i understand correctly. Can someone explain like i'm five how can i make it work without having to first create the key:value pairs in the object?
Thanks in advance!
P.S. They also have to be reactive.
Vue set should do the work only your using it the wrong way:
Adds a property to a reactive object, ensuring the new property is
also reactive, so triggers view updates. This must be used to add new
properties to reactive objects, as Vue cannot detect normal property
additions (e.g. this.myObject.newProperty = 'hi').
But the function arguments looks like this
{Object | Array} target
{string | number} propertyName/index
{any} value
https://v2.vuejs.org/v2/api/#Vue-set
In your case it should be:
Vue.set(state.dataObject, 'total_operation_time', payload[1]);
Vue.set(state.dataObject, 'machine_name', payload[2]);
For example, if I have an object like:
{"angeredoutsidecontrol":"1","difficultiespileup":"2"}
And then later in a for loop I can access the key of angeredoutsidecontrol , how can I get the value returned as 0, which would represent which place in the object this key is?
There is no guaranteed order for keys of an object.
Definition of object from an old - but still effective in this case - documentation:
4.3.3 Object
An object is a member of the type Object. It is an unordered
collection of properties each of which contains a primitive value,
object, or function. A function stored in a property of an object is
called a method.
If order really matters to you, use array instead. For example:
[{ "angeredoutsidecontrol": "1" }
{ "difficultiespileup": "2" }];
The order of JSON objects is not maintained, so you can't do this.
[Is the order of elements in a JSON list maintained?
var myMoods = ["angeredoutsidecontrol","difficultiespileup"];
and
myMoods.indexOf( 'angeredoutsidecontrol' )
gives you position in your list
I have two objects. One is the master data, another is a similar object but contains certain properties that I am using and is a subset of the master data. Please find below the two objects:
$scope.masterData = {
"StoresForOrgs": {
"PPP0001188": ["007071","007073","007079"],
"PPP0001189": ["007075","0070756","0070789"],
"PPP0001190": ["007075","0070756","0070789", "00707893", "00707899"]
}
}
$scope.masterDataForDisplay = {
"StoresForOrgsDisplay": {
}
}
If in my code I do
$scope.masterDataForDisplay = $scope.masterData;
this is linking both the objects and if I change the masterDataForDisplay it is changing the masterData as well. Now I understand that comparing these two would create the same reference and this could be avoided by using then
try this
$scope.masterDataForDisplay = JSON.parse(JSON.stringify($scope.masterData));
but even when the code is not executed this is happening. Are the objects being initialized before?
use this:
$scope.masterDataForDisplay = angular.copy($scope.masterData);
instead of
$scope.masterDataForDisplay = $scope.masterData;
copy() : Creates a deep copy of source, which should be an object or an array. So they dont share the same reference
I have a nested array of the form :
$scope.itinerary =
[
[
{name:'x'},
{name:'y'},
{name:'z'}
],
[
{name:'a'},
{name:'b'},
{name:'c'}
]
]
And I am doing a $watchCollection using the following :
$scope.$watchCollection(function () {
return $scope.itinerary;
},
function () {
console.log("Changed")
}
);
But the console.log() is only executed if one of the sub array is deleted or a new array is inserted. If I move an element from One array to another, nothing happens. (eg when I move {name:'a'} from one array to another, nothing happens). How do I put a watch on the nested Array ?
Use deep watch
The $watch() function takes a third, optional argument for "object equality." If you pass-in "true" for this argument, AngularJS will actually perform a deep-object-tree comparison. This means that within each $digest, AngularJS will check to see if the new and old values have the same structure (not just the same physical reference). This allows you to monitor a larger landscape; however, the deep object tree comparison is far more computationally expensive.
$scope.$watch('itinerary',function (newVal,oldVal) {
console.log(newVal)
},true);
Rather than use $watchCollection, you should use $watch with a third argument set to true.
This will works, but it is also a bad idea for performance if the array is large, so use with caution.
Comparison is done using angular.eaquals comparing to a copied object obtained with angular.copy.
More details at https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch
I was implementing an array for my ember data property
DS.JSONTransforms.array = {
serialize: function(value) {
return Em.isNone(value) ? [] : value ;
},
deserialize: function(value) {
return Em.isNone(value) ? [] : value ;
}
};
And I created this jsbin for test to add and remove items to the array http://jsbin.com/avENazE/4/edit
If I check the console
model.get('pages').push('hi');
console.log(model.get('pages'));
I can see that the new items are corectly add to the array, but are not displayed on the view.
Also the count property is not updated and this error shows on the console on save the model
Uncaught TypeError: You must pass a resolver function as the sole argument to the promise constructor
The make the view be aware of changes of the representing model data you need data binding to work properly. To get data binding to work properly you need to use the correct functions that are sensible to bindings, so in the case of operations done to an array you can't just use vanilla push but instead pushObject or the counterpart removeObject, the same applies for setting a new value to a property, while dot notation will work it will not update you bindings therefore .set() and .get() need to be used etc.
So that said, here your working jsbin.
Hope it helps.