Use variables from other Vue instances and cross reference them - javascript

I have 2 different parts of the website
First: is it ok to use one instance in another especially with v-model, is this have any disadvantages.
Second: Is there any way I can cross reference each other, like footer in aside even though one is declared before the other. I get an error with this code. "footer is undefined"
My JS:
var aside = new Vue({
"el":"aside",
data:{
name:"Peylan"
}
});
var footer= new Vue({
"el":"footer",
data:{
companyname:"Company Inc"
}
});
My HTML
<aside><h3 v-bind="footer.companyname"></h3></aside>
<footer>
<input type="text" v-model="aside.name">
</footer>

Standard way of handling what you want is using a shared Vuex store.
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>
<aside><h3 v-text="footer.companyname"></h3></aside>
<footer>
<input type="text" v-model="aside.name">
</footer>
<script>
const store = new Vuex.Store({
strict: false,
state: {
aside: {
name:"Peylan"
},
footer: {
companyname:"Company Inc"
}
}
});
var aside = new Vue({
store,
"el":"aside",
data:{},
computed: {
...Vuex.mapState(['aside', 'footer'])
}
});
var footer= new Vue({
store,
"el":"footer",
data:{},
computed: {
...Vuex.mapState(['aside', 'footer'])
}
});
</script>
The demo above is a very simplified way of using it. For optimal usage (like with getters, actions and mutations) consider Vuex's official docs.
Or you can use a computed property on both, like below.
This creates a bit of a chicken and egg issue, that's why you need to use .$mount() in this case.
<script src="https://unpkg.com/vue"></script>
<aside><h3 v-text="footer.companyname"></h3>
</aside>
<footer>
<input type="text" v-model="aside.name">
</footer>
<script>
var aside = new Vue({
data:{
name:"Peylan"
},
computed: {
footer() { return footer; }
}
});
var footer = new Vue({
data:{
companyname:"Company Inc"
},
computed: {
aside() { return aside; }
}
});
aside.$mount("aside");
footer.$mount("footer");
</script>

Related

How to dynamically add part of an object with an arg in a vue method

Super simple question but i've never been able to solve it.
Say we have some data:
section: {
option1: true,
option2: true
}
and on a button we have:
<button #click="toggle(option1)">
How do I dynamically paste 'option1' arg into something like this:
toggle(opp){
console.log(this.section.opp)
}
Because currently it's literally looking for this.section.opp, and opp doesn't exist in the data.
Use this.section[opp] instead of this.section.opp as opp contains dynamic value and can not access directly with dot(.) notation as it is containing a different value.
Working Demo :
new Vue({
el: '#app',
data: {
section: {
option1: true,
option2: true
},
result: null
},
methods: {
toggle(opp) {
this.result = this.section[opp];
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="toggle('option1')">Click Me</button>
<p>Result: {{ result }}</p>
</div>

Vue not working correctly with the html (refreshing when I press a button when it isn't supposed to)

I am having a problem where my vue doesn't work correctly.When I press the button it clears out the input(it shouldn't) and does nothing.The variables codigo and payload do not show anything in the screen. Even when I change them via console. It first was having the issue where the 'app' tag wasn't being found by the script even with it on the bottom. To solve it I had to add the line Vue.config.silent=true which made the warning disappear but the code still doesn't work. I am new to vue and web design so expect basic mistakes. I am running it in the 'node' docker image container.
<!DOCTYPE html>
<html>
<head>
<title>Vue test</title>
</head>
<script src="https://cdn.jsdelivr.net/npm/vue#2/dist/vue.js" ></script >
<script>
Vue.config.silent = true;
</script>
<body>
<h2>Manipulador de Recursos</h2>
<br>
<div id='app'>
<form>
URL do Recurso: <input type="text" v-model="recurso" size=50><br><br>
Repr. do Recurso: <input type="text" v-model="repr" size=100><br><br>
Metodo HTTP:
<button v-on:click="doGet">GET</button>
<button v-on:click="doPost">POST</button>
<button v-on:click="doPut">PUT</button>
<button v-on:click="doDelete">DELETE</button> <br><br><br>
</form>
<b>Retorno:</b><br><br>
Codigo HTTP: <span v-bind:id="codigo"></span>
<br><br>
Payload: <span v-html="payload"></span>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script defer >
var myapp = new Vue({
el: "app",
data: {
"codigo":"",
"payload":"",
},
methods:{
// GET
"doGet" : function() {
console.log("GET")
this.clear();
var url = this.recurso;
axios
.get(url)
.then(function (response) {
this.codigo = response;
this.payload =response.data ;
console.log (response);
})
.catch(function (error){
this.codigo = error;
})
},
// POST
doPost : function() {
console.log("POST")
this.clear();
var url = this.recurso;
var data = this.repr;
axios
.post(url, data)
.then((response) => {
this.codigo = response;
this.payload =response.data ;
console.log(response)
})
.catch((error) => {
this.codigo = error;
})
},
//(...)
}
})
</script>
</html>
You don't want to prevent the click action, as suggested above, but the submit action of the form.
<form #submit.prevent="doGet()">
<!-- form stuff -->
</form>
At first, your methods must be inside methods property:
var myapp = new Vue({
//.......
data: {
codigo: "",
payload: ""
},
methods: {
doGet: function() { /*.......*/},
doPost: function() { /*.......*/}
}
})
and in this example your buttons can do default action (the form sending) so it may be necessary: v-on:click.prevent="doGet()".
This solved it Simple vue app doesn't show anything :
Because you didn't render anything in your root component.
In your index.html, render the app component:
<div id="app"> <app> <!-- html code, buttons etc--> </app> </div>
Adding the tags.
Along with this: adding type="button" to the buttons because since they where inside a forms they refreshed the page.
And finally I added:
document.addEventListener("DOMContentLoaded", function(event) {
Around my var myapp = new Vue({

modifying data variable in vue.js using axios

Here is my script :
<html>
<script src="https://unpkg.com/vue"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.0/axios.js"></script>
<body>
<div id="app-3">
<span v-if="seen">{{ textFromApi }}</span>
</div>
<br/>
<script type="text/javascript">
var app3 = new Vue({
el: '#app-3',
data: {
seen: true,
textFromApi: "hello"
},
methods: {
getData() {
return axios.get('https://jsonplaceholder.typicode.com/posts/1')
},
},
created: function () {
this.textFromApi = this.getData();
}
})
</script>
</body>
</html>
I'm trying to modify this.textFromApi from the call of this api: https://jsonplaceholder.typicode.com/posts/1
but my this.textFromApi doesn't seems to update, any ideas why?
Here is a fiddle code:
https://jsfiddle.net/bussiere/5t3v013o/
Edited from remark just below
Regards and thanks
created() is a lifecycle hook, it should be at the same level as data, methods, computed etc. Not a child of methods (so if you nest created() in methods() it will never get executed unless you call the method).
You also don't do anything with the axios promise, you should process it using then ().
<script src="https://unpkg.com/vue"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.0/axios.js"></script>
<body>
<div id="app-3">
<span v-if="seen">{{ textFromApi }}</span>
</div>
<br/>
<script type="text/javascript">
var app3 = new Vue({
el: '#app-3',
data () {
return {
seen: true,
textFromApi: { title: 'empty'}
}
},
methods: {
getData() {
return axios.get('https://jsonplaceholder.typicode.com/posts/1').then(response => {
this.textFromApi = response.data
})
},
},
created: function () {
this.getData();
}
})
</script>
</body>
</html>

Append new Item to a list in Vue 2

I have a very simple form which gets name and age from user and add this to a list.
You can check that on JSFiddle.
Here is HTML :
<div id="app">
<ul>
<li v-for="user in users">{{ user.name +' '+ user.age }}</li>
</ul>
<hr>
<form v-on:submit.prevent="addNewUser">
<input v-model="user.name" />
<input v-model="user.age" />
<button type="submit">Add User</button>
</form>
</div>
Here is Vue code:
new Vue({
el: '#app',
data: {
users: [{name:"Mack", age:20}],
user: {name:"", age:0}
},
methods: {
addNewUser() {
this.users.push(this.user);
}
}
});
The Problem
The problem is where I trying to add more than one user to the list. As you can see, when I type new value for the new user, previous values of recently added users change too!
How can I fix it?
When you push this.user to the array you're pushing the reference to that data. Instead, create a new object using the data from the user object:
this.users.push({ name: this.user.name, age: this.user.age })
You should be creating a new object which should be decoupled from the data.
new Vue({
el: '#app',
data: {
users: [{name:"Mack", age:20}],
user: {name:"", age:0}
},
methods: {
addNewUser() {
let newUser = {
name: this.user.name,
age: this.user.age
};
this.users.push(newUser);
}
}
});
One more thing I'd suggest; I see that you are interpolating the value of the name and age by writing {{ user.name +' '+ user.age }} while instead you could convert that into a computed property and make it more reusable.
If you're using lodash, try this.
this.users.push(_.cloneDeep(this.user))

Vuejs will not render component correctly when trying to loop thru array data or v-for

<!DOCTYPE html>
<html lang="en">
<head>
<script src="js/vue.js"></script>
<meta charset="UTF-8">
<title>V-for example</title>
</head>
<body>
<script type="x/template" id="testTemplate">
<div><h1>{{name}}</h1>
<p>{{Age}}</p></div>
</script>
<div id="example">
<div id="filler">
<template v-for="person in people">
<test-component name="{{person.name}}"></test-component>
</template>
</div>
</div>
<script>
var newComponent = Vue.extend({
template: '#testTemplate',
props: ['name'],
data: function () {
return {
Age: 1010
}
}
});
Vue.component('test-component', newComponent);
new Vue({
el: '#example',
data: {
people: [{
name: 'jason',
age: 15,
complete: true
}, {
name: 'Jeremy',
age: 20,
complete: false
}]
},
ready: function () {
var divoutput = document.querySelector('#filler');
alert(divoutput.innerHTML);
len = this.$data.people.length;
for (i = 0; i < len; i += 1) {
var nameT = this.$data.people[i].name;
divoutput.innerHTML += '<test-component name="' + nameT + '"></test-component>';
}
},
});
</script>
</body> </html>
I'm trying to take all of the people in the Vue data array and inject it into a component and add it to a innerHTML of a div during the Vue.ready() function. I show that result is being injected in to the "filler" array but the components them selves are not being rendered properly. If I make a manual instance of my component it works fine.
You shouldn't try to add Vue component using innerHTML. That's managing the DOM yourself, just let Vue do that on its own. Here is a fiddle:
https://jsfiddle.net/xccjsp4b/
I changed the script template to a div because I'm not certain you can use the script tag like that (although I could be wrong). Then you just use a v-for to loop through the people and pass the relevant data as properties. If each person is going to have their own age, you want it to be a property not a data variable.
Also, use the shorthand binding of :name="person.name" rather than name="{{person.name}}". The : tells Vue to evaluate the expression.

Categories

Resources