vuejs bind url from data to click method - vue.js

I have a set of data that has urls nested in the data model. I want to bind the url from from the data to click event. Right now it does not get the exact url just the variable. It should open the url in the data in a blank tab.
new Vue({
el: "#app",
data: {
chocs: [
{ url: "https://yahoo.com"},
]
},
methods: {
myclick2: function(choc){
alert("test")
window.open(choc.url)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>
my hat
</h2>
<button v-on:click="myclick2(choc)">
my link
</button>
</div>

There are multiple little error in your code
First the correct code:
new Vue({
el: "#app",
data() {
return {
chocs:
{ url: "https://yahoo.com"},
}
},
methods: {
myclick2: function(){
alert("test ")
window.open(this.chocs.url, "_blank")
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>
my hat
</h2>
<button v-on:click="myclick2()">
my link
</button>
</div>
List of errors:
the data part is written as data(){return{...}}
in your function you were calling choc instead of chocs (you have access to the data, don't pass something that is undefined as parameter)
because you use data, you need to call it with this
based on the structure from chocs, you have an object in an array (the first place in the array; index 0) OR based on your comment -> remove this brackets [ ]
if you want to open a new window, you can add "_blank"

You have defined the data as an array named chocs. Containing an object with an url.
This would be saved as follows:
cohc: [
{ url: "https://yahoo.com/" }
]
This array could contain more items, but right now it only contains this one item. If you want to "open" that item you would do something like the following:
cohcs: [
{ url: "https://yahoo.com/" }
]
console.log(cohcs[0]) // returns: { url: "https://yahoo.com/" }
The 0 is the index of the array.
In case of the code provided above, you can define your v-on:click event like this:
<button v-on:click="myclick2(chocs[0])">
If you only want to save one link. you could also define your data as
data: {
chocs: { url: "https://yahoo.com"}
},

Related

user info is not loading in vue component after login

I am using localstorage to save user info after a successful login. Then I want to put a v-if condition to filter whether the user is logged in or not. But the problem is, the localStorage returning null while I am trying to parse it in components. I am sharing the codes from component here :
data() {
return {
currentUser : {}
}
},
mounted() {
this.currentUser = localStorage.getItem('userInfo')
}
From the Template :
<span v-if="currentUser" class="dropdown-item dropdown-header text-right">{{ currentUser.name
}}</span>
From console :
You can simply achieve that by just considering below two points :
While storing the data in localStorage, store it as a string. In the below demo I will use JSON.stringify() to convert the userInfo object into a string.
While fetching the data from localStorage, parse it using JSON.parse()
Working Demo :
new Vue({
el: '#app',
data: {
userInfo: null
},
mounted() {
this.getUserInfo();
},
methods: {
saveUserInfo() {
const userInfo = {
id: 1,
name: 'alpha'
}
localStorage.setItem('userInfo', JSON.stringify(userInfo))
},
getUserInfo() {
this.userInfo = JSON.parse(localStorage.getItem('userInfo'));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p> <strong>UserName :</strong> {{ userInfo?.name }} </p>
<button type="submit" #click="saveUserInfo">
Save User Info
</button>
</div>
localStorage store as key-value pair; and the value is a type of string, you should parse it to a JSONObject

How to select text inside input when the input get mounted (Vue3 )

I have this form that I created, basically what its doing is creating a new input with a random value each time I click on ADD_INPUT button. the thing I want is each time I create a new INPUT with random value the value get selected.
Sorry for my very bad English.
I've tried creating a new customized directive like this :
directives: {
focusInput: {
// directive definition
mounted(el) {
el.select()
}
}
},
but it breaks idy
Hoy can use select()
new Vue({
el : '#app',
data : {
text: 'some text'
},
methods : {
select() {
this.$refs.input.select();
},
},
mounted() {
this.select()
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="select">ADD_INPUT</button>
<input type="text" v-model="text" ref="input">
</div>
Composition API
setup() {
const input = ref(null)
function select() {
input.value.select()
}
return {
input,
select
}
}

How to render HTML from a property of items being displayed with v-for loop?

I send an array of objects which each have a .html property that has HTML text in it, e.g. <h1>...</h1> or <h2>...</h2>
I want to have the HTML from each item display one after another in the DOM, like this:
<h1>...</h1>
<h2>...</h2>
<h2>...</h2>
<h1>...</h1>
<h2>...</h2>
However, all of these attempts do not work:
<div v-for="item in outlineItems" v-html="item.html"></div>
displays HTML wrapped in divs: <div><h1>...</h1></div> and <div><h2>...</h2></div>
<template v-for="item in outlineItems" v-html="item.html"></template>
displays nothing
<template v-for="item in outlineItems">{{item.html}}</template>
displays the literal HTML instead of rendering it
<template v-for="item in items"><template v-html="item.html"></template></template>
displays nothing
How can I simply display the contents of the .html property of each item so that the HTML in it renders, without any wrapping elements on it?
You could do it using a single wrapper element for the whole lot by concatenating all the HTML in a computed property:
new Vue({
el: '#app',
data () {
return {
outlineItems: [
{ html: '<h1>Heading 1</h1>' },
{ html: '<h2>Heading 2</h2>' },
{ html: '<h3>Heading 3</h3>' }
]
}
},
computed: {
outlineHtml () {
return this.outlineItems.map(item => item.html).join('')
}
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.js"></script>
<div id="app">
<div v-html="outlineHtml"></div>
</div>
Behind the scenes v-html sets the innerHTML of its corresponding DOM node. A <template> tag doesn't create a DOM node so the innerHTML can't be set anywhere.
I would add that v-html is considered an 'escape hatch'. Where possible you should avoid using it and let Vue create the HTML itself. Generally the approach would be to use a suitable data structure to hold the data (rather than a blob of markup) and then render that data structure within the template.
One possible solution is to create multiple unique components. You can even pass in props, and there are no wrappers
Vue.component('greeting', {
template: '<h1>Welcome to coligo!</h1>'
});
Vue.component('titles', {
template: '<h1>title 1</h1>'
});
Vue.component('title2', {
template: '<h2>Welcome to coligo!</h2>'
});
Vue.component('title3', {
template: '<h3>{{text}}</h3>',
props: ['text']
});
var vm = new Vue({
el: '#app',
data: {
items: [
{ type: 'greeting' },
{ type: 'titles' },
{ type: 'title2' },
{ type: 'title3', text: 'test' }
]
}
});
<script src="https://unpkg.com/vue#2.6.11/dist/vue.js"></script>
<div id="app">
<component v-for="(item,i) in items" :is="item.type" :text="item.text" :key="i"></component>
</div>

Removing last item when rendering in vue.js

I am facing an issue where a item is getting rendered even though there is no associated Title with it as shown in my JSON. Please see the attached screenshot which will make you understand my problem (marked in red). I know this is happening due to lid in my JSON for which vue is rendering that without any associated (i.e Title) values. How do I solve this issue. Is there a way to remove the last item when rendering or is there any other way ?. I need the lid in this.dino but do not need it when rendering in my vue-app. Is there a way to pop out the last item from the JSON when rendering.
<div id="vue-app">
<div id="myList" v-for="item in items">
<p>{{item.Title}}</p>
<button v-on:click="loadmore()" class="fluid ui button">Load More</button>
Below is my vue function
new Vue({
el: '#vue-app',
delimiters: ['[[', ']]'],
data: {
dino: d_var,
cati: d_catox,
items: []
},
methods: {
loadmore: function () {
axios.get(this.dino)
.then(response => {
this.items.push(...response.data);
this.dino = "/api/search/" + this.items[this.items.length - 1].lid + "/" + this.cati;
})
}
}
})
Below is my JSON
[
{
"Title": "HealthXP1"
},
{
"Title": "HealthXP2"
},
{
"Title": "HealthXP3"
},
{
"lid": "A1234567890"
}
]
you can use 'v-if' or 'v-show' directive as:
<div id="vue-app">
<div id="myList" v-for="item in items" v-show="item.Title">
<p>{{item.Title}}</p>
<button v-on:click="loadmore()" class="fluid ui button">Load More</button>
that will show that item on the list if the item.Title is defined, otherwise it will not be rendered in DOM

How is the method Total being called in this example

I see in the code below how the list item's class and state is being modified but I don't understand where or how the total() method is being triggered. The total is added to the markup in the <span>{{total() | currency}}</span> but there is no click event or anything reactive that I see in the code that is bound to it.
<template>
<!-- v-cloak hides any un-compiled data bindings until the Vue instance is ready. -->
<form id="main" v-cloak>
<h1>Services</h1>
<ul>
<!-- Loop through the services array, assign a click handler, and set or
remove the "active" css class if needed -->
<li
v-for="service in services"
v-bind:key="service.id"
v-on:click="toggleActive(service)"
v-bind:class="{ 'active': service.active}">
<!-- Display the name and price for every entry in the array .
Vue.js has a built in currency filter for formatting the price -->
{{service.name}} <span>{{service.price | currency}}</span>
</li>
</ul>
<div class="total">
<!-- Calculate the total price of all chosen services. Format it as currency. -->
Total: <span>{{total() | currency}}</span>
</div>
</form>
</template>
<script>
export default {
name: 'OrderForm',
data(){
return{
// Define the model properties. The view will loop
// through the services array and genreate a li
// element for every one of its items.
services: [
{
name: 'Web Development',
price: 300,
active:true
},{
name: 'Design',
price: 400,
active:false
},{
name: 'Integration',
price: 250,
active:false
},{
name: 'Training',
price: 220,
active:false
}
]
}
},
// Functions we will be using.
methods: {
toggleActive: function(s){
s.active = !s.active;
},
total: function(){
var total = 0;
this.services.forEach(function(s){
if (s.active){
total+= s.price;
}
});
return total;
}
},
filters: {
currency: function(value) {
return '$' + value.toFixed(2);
}
}
}
</script>
EDIT:
Working example https://tutorialzine.com/2016/03/5-practical-examples-for-learning-vue-js
So I believe the explanation for what is happening is that data's services object is reactive. Since the total method is being bound to it, when the toggleActive method is being called, it is updating services which causes the total method to also be called.
From the docs here 'How Changes Are Tracked' https://v2.vuejs.org/v2/guide/reactivity.html
Every component instance has a corresponding watcher instance, which records any properties “touched” during the component’s render as dependencies. Later on when a dependency’s setter is triggered, it notifies the watcher, which in turn causes the component to re-render.
Often I find simplifying what is going on helps me understand it. If you did a very simplified version of above it might look like this.
<div id="app">
<button #click="increment">Increment by 1</button>
<p>{{total()}}</p>
</div>
new Vue({
el: "#app",
data: {
counter: 0,
},
methods: {
increment: function(){
this.counter += 1;
},
total: function(){
return this.counter;
}
}
})
working example: https://jsfiddle.net/skribe/yq4moz2e/10/
If you simplify it even further by putting the data property counter in the template, when its value changes, you would naturally expect the value in the template to also be updated. So this should help you understand why the total method gets called.
<div id="app">
<button #click="increment">Increment by 1</button>
<p>{{counter}}</p>
</div>
new Vue({
el: "#app",
data: {
counter: 0,
},
methods: {
increment: function(){
this.counter += 1;
},
}
})
working example: https://jsfiddle.net/skribe/yq4moz2e/6/
When you update the data, the template in the components rerendered. That means that the template will trigger all methods bind to the templates. You can see it by adding dynamic date for example.
<div id="app">
<button #click="increment">Increment by 1</button>
<p>{{total()}}</p>
<p>
// Date will be updated after clicking on increment:
{{date()}}
</p>
</div>
new Vue({
el: "#app",
data: {
counter: 0,
},
methods: {
increment: function(){
this.counter += 1;
},
total: function(){
return this.counter;
},
date: function() {
return new Date();
}
}
})