I'm very new to vue, so this is properly a basic question. I have a value in my template from an parsed object prop like this:
<h1>{{myval.theme}}</h1>
This gives and display the value in the browser. However, I need to obtain the value and store it in the data section of the instance. How can I store the data in the "getTheValue" data string? This is what I currenct have, and this does not work:
props: {
myval: Object
},
data() {
return {
getTheValue: this.myval.theme
};
},
The best way its to use computed here
computed: {
getTheValue() {
return this.myval.theme
}
}
and call it same way:
this.getTheValue
its best solutions - cached, non-reactive
also if you still want to use data you can assign in lifetime-hooks like:
mounted() {
this.getTheValue = this.myval.theme
}
But its crude solution, and I highly recommend to use computed variant
Related
Having an object similar to:
const data = {
tasks: {
projects: [
name:'Project Name',
filters: [
{
name:'First Project Filter',
checked:false,
onChange:(event) => {
console.log(this.checked)
}
},
...
],
...
],
...
},
...
}
The problem at hand is how to reference the checked property without drilling through the entire object.
In the case above, it throws an error because this is undefined, so referencing this.checked is invalid.
I could extract from the event data properties so that I can get the
whole reference such as tasks.projects[0].filters[0].checked, but I
am wondering if an easier method is available.
The ideal solution would be a way to reference the surrounding properties of the function without traversing the entire object. Surely the function has a way to know that it is inside of an object so maybe something like parent().checked ?
If relative: I am using node.js and react to use this object to render a filtered sidebar that works with context to filter the data-set. I don't think that is relative as this seems like a pure JavaScript OOP situation.
This is probably a simple question, but can someone pls clarify the following javascript code?
// 'response' is the JSON data gotten from the backend:
....then(response => {
this.myVar = response.data;
});
// 'myVar' is initialised here:
data: function() {
return {
myVar: null
};
}
I can see how we declare a property 'data' that points to a function that returns an initialised variable 'myVar'.
I don't quite get how 'myVar' is set to the response value. I assume it is a JS technique? Can someone please explain this or provide me a link to such?
* EDIT *
From the responses, it seems I didn't supply enough info (sorry about that - I was assuming it be a simple JS issue). I extracted this code from a tutorial, and it works. The code excerpt is from a .vue file. So I supply the whole file here. The question is still the same.
<template>
<div>
<button class="my-button" v-text="myVar.name" :type="type">My Button</button>
</div>
</template>
<script>
export default {
mounted() {
// The "api/vue" route calls a controller that supplies a JSON object with a single name=>value pair
axios.post("api/vue", {}).then(response => {
// ?? How exactly does myVar get allocated the JSON data?
this.myVar = response.data;
});
},
// initiate the 'myVar' variable
data: function() {
return {
// ?? this object is delared here and somehow accessible to the whole file?
myVar: null
};
},
};
</script>
this whole code makes a Vue Component. In a Vue Component, initial data should be a function, which will be invoked when component created. the object that returned by data() is the initial data for the component, and it's observable(observable means, if you change it, something other will be changed also). the techniche of javascript used here is Object.defineProperty : https://v2.vuejs.org/v2/guide/reactivity.html
base on your code, it says you have a initial data named 'myVar', if you change the value of 'myVar', the dom which bound with 'myVar' will change automatically. in your code, it's the text of the button.
mounted
this is a life-cycle hook, it will be invoked after the component mounted into the dom.
you called an AJAX at here, then you used arrow function to deal with the result of AJAX. arrow function means it's this will not change (here , this equals the Vue Component).
we already have a initial data 'myVar' on this component, now we change it:
this.myVar = response.data;
because it's observable/reactive, the text of the button in your template will be changed.
by the way, your initial myVar is null, so your initial text myVar.name will cause an error
// 'response' is the JSON data gotten from the backend:
....then(response => {
this.myVar = response.data;
});
In this first method, you are fetching data from a server, and assigning it this.myVar (not myVar). so it's local to the component, however...
In the code below, whenever you call data(), you are returning an object with a property myVar encapsulated in it. it is not the same as this.myVar.
// 'myVar' is initialised here:
data: function() {
return {
myVar: null
};
}
I'm not sure what you're trying to achieve here, but these variables are unrelated. And maybe the naming needs some work too, so it's easier for us to see what the purpose of this code is. Either way, if this.myVar is a variable owned by your component, the object returned from the data() method will not have any effect on it, since it's structure is different. the myVar in the Object you are returning in data is a new variable, local to that object.
When I started with Vue.js I read about a case where you return a data property with return and sometimes without. I cannot find that article anymore that's why I'm asking here.
That's how I use it today
data: function () {
return {
myData : "data"
}
},
But that's how I see it in documentation very often - don't know the difference anymore:
data: {
myData: "data"
},
https://vuejs.org/2016/02/06/common-gotchas/#Why-does-data-need-to-be-a-function
Why does data need to be a function?
In the basic examples, we declare the data directly as a plain object. This is because we are creating only a single instance with new Vue(). However, when defining a component, data must be declared as a function that returns the initial data object. Why? Because there will be many instances created using the same definition. If we still use a plain object for data, that same object will be shared by reference across all instance created! By providing a data function, every time a new instance is created, we can simply call it to return a fresh copy of the initial data.
Making an SPA using Polymer, and I need my custom components to all use a common custom component which represents my backend API and is responsible of GET-ting/POST-ing data from/to the API. It also serves as a "cache" and holds the data to display. This way, all the components that have access to this single element will share the same data.
So what I want to do is this... :
<my-api
users="{{users}}"
products="{{products}}">
</my-api>
...but programmatically, as <my-api> is not declared in all of my components but once in the top one and then passed down through the hierachy by JavaScript:
Polymer({
is: 'my-component',
properties: {
api: {
observer: '_onApiChanged',
type: HTMLElement
},
products: {
type: Array
},
users: {
type: Array
}
},
_onApiChanged: function(newVal, oldVal) {
if (oldVal)
oldVal.removeEventListener('users-changed', this._onDataChanged);
// Listen for data changes
newVal.addEventListener('users-changed', this._onDataChanged);
// Forward API object to children
this.$.child1.api = newVal;
this.$.child2.api = newVal;
...
},
_onDataChanged: function() {
this.users = this.api.users; // DOESN'T WORK as 'this' === <my-api>
this.products = this.api.products; // Plus I'd have to repeat for every array
}
});
Does Polymer offers a built-in way to do this ? Can I create a double curly braces binding programmatically ?
I would likely architect this slightly differently: passing down the products/users arrays declaratively taking advantage of Polymer's binding system. Or you could write your my-api element in such a way that they all share state and the first declared one is the primary while future declared ones are replicas. This would let you declare them wherever you need them and bind to the values via Polymer's normal ways.
But to answer your question, there's currently no way to easily programmatically setup the same kind of binding without using private Polymer APIs.
To avoid repeating as much and for the binding issue you were having you could use Polymer's built-in listen and unlisten methods:
Polymer({
is: 'my-component',
properties: {
api: {
observer: '_onApiChanged',
type: HTMLElement
},
products: {
type: Array
},
users: {
type: Array
}
},
_onApiChanged: function(newVal, oldVal) {
var apiProperties = ['users', 'products'];
if (oldVal) {
apiProperties.forEach(function(prop) {
this.unlisten(oldVal, prop + '-changed', '_onDataChanged');
});
}
// Listen for data changes
apiProperties.forEach(function(prop) {
this.listen(newVal, prop + '-changed', '_onDataChanged');
});
// Forward API object to children
this.$.child1.api = newVal;
this.$.child2.api = newVal;
...
},
_onDataChanged: function() {
this.users = this.api.users; // `this` should be the element now
this.products = this.api.products;
}
});
Given how this is a common pattern you're doing, you could probably get a lot of benefit out of extracting some of these things into a Behavior that abstracts away the binding/unbinding and API element forwarding.
Another optimization you may could make work would be to to look at the event passed to _onDataChanged to see if you can infer which value changed and update your corresponding property. This could prevent you needing to add a line for every property.
I ended up using an other solution. Instead of manually passing the top <my-api> element down the hierarchy any element that needs access to this shared data declares its own <my-api>.
Then in the <my-api> element's declaration I made that all instances use the same arrays references. So whenever I update one they all get updated, and I don't have to pass anything down the HTML hierarchy, which makes things a LOT simpler.
I am creating a generic table view that can be used with different collections. Here is an example of what I'm trying to do:
...
getModelIdAttribute: function () {
return this.collection.__proto__.model.prototype.idAttribute;
},
getModelFromRow: function (HTMLrow) {
return this.collection.get(this.dataTable.row(HTMLrow).data()[this.getModelIdAttribute()]);
},
...
The data() function returns an object with the attributes that were used to create the model, but I want to account for different idAttributes.
Currently, my way works - but __proto__ is deprecated and it seems like there should be an easier way that I am missing?
Thanks