Vue bind to dynamic json node(create if not exists) - vue.js

I'm trying to make v-model to bind to dynamic node in a json object (if not exists create node). The response node will come as a config.
Eg:
<v-text-field :="responseNode"></v-text-field>
where responseNode will be some string like dataObject.Response.ParentObject.ChildVal
So I will expect something like this will get created
dataObject:{
Response:{
ParentObject:{
ChildVal:10
}
}
}

I tried to parse the responseNode string to convert it into an object and then binding that into an HTML template inside v-model.
Live Demo :
new Vue({
el: '#app',
data: {
responseNode: 'dataObject.Response.ParentObject.ChildVal',
childValue: 10,
inputValue: null
},
mounted() {
let tempObject = {};
let container = tempObject;
this.responseNode.split('.').map((k, i, values) => {
container = (container[k] = (i == values.length - 1 ? this.childValue : {}))
});
this.inputValue = tempObject;
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="inputValue.dataObject.Response.ParentObject.ChildVal"/>
</div>

Related

Get name model in vue js with help id input or name

Can i get model name if i now id input?
For examle
<input v-model="data.name" id="name_db">
I have in db value for data.name
Before vue i did this:
valuesFromDb.forEach(data=>{
if(data.fromdb==name_db)
$("#name_db").val(data.fromdb)
}
...
But it can't work with vueJS
I know i can do this:
data.name = data.fromdb
But i have many data in db and before vue i put data with help forloop.
Model and id have different names ​​and it will take a long time to manually iterate through all the data
Now i want get model name and put value to it
Somethinks like this:
var modelName = $("#name_db").getModelNameVue();
modelName=data.fromdb
If i do this, in input value change but in data dont
data(){
return{
mainPdf:{
left: 5,
bottom:5,
top:5,
right:5
}
}
}
<input v-model="mainPdf.left" id="left_margin">
<input v-model="mainPdf.bottom" id="bot_margin">
<input v-model="mainPdf.isMargin" id="right_margin">
<input v-model="mainPdf.isMargin" id="up_margin">
getFromdb(){
api.getFromdb(e=>{ // string=e
var string = "left_margin=0&bot_margin=1&right_margin=2&up_margin=3"
var rPlus = /\+/g;
$.each( string.split( "&" ), function( index, field ) {
$.each( string.split( "&" ), function( index, field ) {
var current = field.split( "=" );
if( current[ 1 ] && current[ 0 ]) {
var name = decodeURIComponent(current[0].replace(rPlus, "%20"));
var value = decodeURIComponent(current[1].replace(rPlus, "%20"));
$("#"+ name).val(value);
}
});
})
})
I can't dynamic-binding because i can't change name of properties in mainPdf, because i have entity with same fields(left,bottom,top,right) in my backend
==========i found solution
i used dispatchEvent
$("#" + NAME).prop("checked", true);
$("#"+ NAME")[0].dispatchEvent(new Event('change')); //or input
Using Vue.js and dynamic programming techniques, it's a piece of cake.
Vue.component('dynamic-binding', {
template: `
<div style="display: flex;">
<input
v-for="field in Object.keys(mainPdf)" :key="field"
v-model="mainPdf[field]"
>
</div>
`,
data() {
return {
mainPdf: {},
};
},
methods: {
fromDb(val = 'left_margin=0&bot_margin=1&right_margin=2&up_margin=3') {
const db = new URLSearchParams(val);
this.mainPdf = Object.fromEntries(db);
},
},
mounted() {
this.fromDb();
},
});
new Vue({ el: '#app' });
<div id="app">
<dynamic-binding></dynamic-binding>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

How to inject object value to v-text when key was added during usegn aplication?

This is my obj form backend
myObj = {
name:'nr123',
empty:''
}
On click function adds new key: value
function userClick(){
this.myObj.status= "accept";
console.log(this.myObj)
}
clg returns
myObj = {
name:'nr123',
empty:'',
satus:'accept'
}
but when i try to display it
<v-text>
Acceptation status {{ myObj.status }}
</v-text>
it won't work.
And this is iteresting when i use "epty" (alredy declared key) to carry 'accept' every thing works fine
so how to show acceptation status when it was added in a midle of the process?
(myObj is one of dinamicly created objects kept in array. Each of myObj's can assume diferent acceptation status)
You can use computed property.
Demo :
new Vue({
el: '#app',
data() {
return {
myObj: {
name:'nr123',
empty:''
}
}
},
computed: {
newObj: function() {
this.myObj.status = 'accept';
return this.myObj;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p v-text="newObj.status"></p>
</div>

Looping out input attributes?

I have an input inside a component and wish to pass in an arbitrary number of
attributes depending on the situation in which it is used:
<input type="text" data-a="a" data-b="b" data-c="c">
I have a prop with the attributes but how can I loop them out to build attributes on an input?
Element has a dataset property. You can iterate it with Object.keys. And if you want to iterate all attributes of the element, use getAttributeNames() method.
var el = document.getElementsByTagName('input')[0]
// data-* attributes
Object.keys(el.dataset).forEach(key => {
console.log('data-' + key, el.dataset[key])
})
// all attributes
el.getAttributeNames().forEach(name => {
console.log(name, el.getAttribute(name))
})
<input type="text" data-a="a" data-b="b" data-c="c">
You can set the attributes of an element using the v-bind directive, which can be passed an object where each key is the attribute and value is the value for the attribute.
You say you are passing the attributes you'd like to bind as a prop. I'm going to assume your data structure since you didn't specify (if this isn't your data structure, you would need to create a computed property to format your data in this way):
{ 'data-a': 'a', 'data-b': 'b', 'data-c': 'c' }
And then, assuming the name of your prop is attrs, you would simply add the attributes to the input using v-bind like so:
<input type="text" v-bind="attrs">
Here's an example:
Vue.component('child', {
template: `<input type="text" v-bind="attrs">`,
props: {
attrs: { Object, default: () => ({}) }
}
});
new Vue({
el: '#app',
data() {
return {
myAttrs: {
'data-a': 'a',
'data-b': 'b',
'data-c': 'c',
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<child :attrs="myAttrs"></child>
</div>
You can use vuejs render function like
Vue.component('child', {
data() {
return {
attrs: {
'data-a': 'a',
'data-b': 'b',
'data-c': 'c'
}
}
},
render(h) {
return h('input', {
attrs: {
...this.attrs
}
})
}
});
This is how you can set attributes dynamically. Fiddle
Template =>
<div id="app">
<p class="text" v-bind="options">{{ message }}</p>
</div>
Script =>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
propName: 'hello'
},
computed: {
options() {
return {
[`data-${this.propName}`]: this.message
}
}
}
})

Is it possible to use a v-model from inside a component template?

Can the v-model syntax be used from inside a Vue component template?
The following works as expected when included directly in an .html
<input type="text" v-model="selected_service_shortname">
Putting the following stuff into a component template does not work.
var service_details = {
template: `
...
<input type="text" v-model="selected_service_shortname">
...
`
};
vm = new Vue({
el: "#app",
components: {
'service-details': service_details
},
Results in vue.min.js:6 ReferenceError: selected_service_shortname is not defined
Changing the template syntax to
<input type="text" v-model="this.$parent.selected_service_shortname">
Seems to halfway work -- changes applied externally to selected_service_shortname appear in the input box as expected. But making changes to the input box directly results in Uncaught TypeError: Cannot convert undefined or null to object
Is what I'm trying to do a supported use case? If so, are there working examples somewhere?
You can implement support for v-model in your component. This is covered in the documentation here.
Here is an example.
var service_details = {
props: ["value"],
template: `
<input type="text" v-model="internalValue">
`,
computed: {
internalValue: {
get() {
return this.value
},
set(v) {
this.$emit("input", v)
}
}
}
};
Basically, v-model, by default, is simply sugar for passing a value property and listening for the input event. So all you need to do is add a value property to your component, and emit an input event. This can also be customized as described in the documentation.
console.clear()
var service_details = {
props: ["value"],
template: `
<input type="text" v-model="internalValue">
`,
computed: {
internalValue: {
get() {
return this.value
},
set(v) {
this.$emit("input", v)
}
}
}
};
new Vue({
el: "#app",
data: {
selected_service_shortname: "some service name"
},
components: {
'service-details': service_details
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
<service-details v-model="selected_service_shortname"></service-details>
<hr>
Selected Service Shortname: {{selected_service_shortname}}
</div>
Used in the parent like this:
<service-details v-model="selected_service_shortname"></service-details>

Content from async XML source doesn't get updated correctly in vue component

Im struggeling with reactivity in vue and need some help.
My component should show content from a XML document. When switching between different XML documents, some components keep their old value and don't reflect the new content. This seems to happen for XML elements, that have the same id. However I use a unique :key attribute in the v-for loop consisting of the XML documents id and the XML elements id.
This only happens, if I set the content using a data property.
<span v-html="value"></span>
...
data() {
return {
value: this.xmlNode.firstChild.nodeValue
};
}
When I set the content directly it works as expected.
<span v-html="xmlNode.firstChild.nodeValue"></span>
HTML
<div id="course">
<button #click="toggle">Change content</button>
<edit-element
v-for="node in courseElementContent"
:xml-node="node"
:key="id + '#' + node.getAttribute('idref')"></edit-element>
</div>
JavaScript:
Vue.component('edit-element', {
template: '<div><span v-html="value"></span></div>',
props: ["xmlNode"],
data() {
return {
value: this.xmlNode.firstChild.nodeValue
};
}
});
new Vue({
el: "#course",
name: "CourseElement",
data: {
id: 1,
courseElementContent: null
},
created() {
this.load();
},
methods: {
toggle() {
if (this.id == 1) this.id = 2;
else this.id = 1;
this.load();
},
load() {
var me = this;
axios.get("content/" + this.id + ".xml").then(
response => {
var doc = new DOMParser().parseFromString(response.data, "text/xml"));
// get all <content> elements
me.courseElementContent = doc.querySelectorAll("content");
});
}
}
});
What am I missing? What should be changed to always reflect the correct value? (Note: I want to use a references data property to easily change "value" just by setting it.)
Thanks for enlightenment.
My interactive fiddle
https://jsfiddle.net/tvjquwmn/
Your data property is not reactive as it refer to a primitive type. It will indeed not be updated after the created step.
If you want it to be reactive, make it computed instead:
Vue.component('edit-element', {
template: `
<div>
<span v-html="direct ? xmlNode.firstChild.nodeValue : value"></span>
<span style="font-size: 60%; color:grey">({{ keyVal }})</span>
</div>`,
props: ["xmlNode", "keyVal", "direct"],
computed: {
value() {
return this.xmlNode.firstChild.nodeValue;
}
}
});
See working fiddle: https://jsfiddle.net/56c7utvc/