vuejs pass data to template html attributes - vue.js

I'm very new to Vuejs.
I see how to pass data (variables) into components, but in my code I need to get thoses variables in the HTML attributes of the template.
Here my HTML :
<div id="activities" class="row text-center activities">
<myimage text="{{ art_text }}" type="art"></myimage>
</div>
Here my Vuejs code (delimiters changed, because of Twig) :
<script type="text/javascript" src="{{ asset('js/vue.js') }}"></script>
<script type="text/javascript">
Vue.component('myimage', {
delimiters: ['${', '}'],
props: ['text', 'type'],
template: '<div class="col-lg-3 col-md-3" style="padding-top: 20px;"><h3><a title="${text}" href="#"><span> <img style="width:220px;" alt="Image ${type}"> </span></a></h3><span>${text}</span></div>'
});
new Vue({
el: '#activities'
});
</script>
But for example, in my template I don't see why "title" attribute don't get the variable ${text} ...
Is there another way to pass data from custom element to HTML attributes of the template ?

The problem is:
Interpolation inside attributes has been removed. Use v-bind or the colon shorthand instead.
Also, per docs:
Mustaches cannot be used inside HTML attributes. Instead, use a v-bind directive.
So, instead of title="${text}" (which is, because you are using custom delimiters, the equivalent of title="{{ text }}"),
Use:
v-bind:title="text"
Or v-bind's shorthand:
:title="text"

Related

Vue Custom directive not working with template tag

I'm facing issue with the below directive, it is working with any tag except the template tag
Vue.directive('count',{
bind(el,b,v){
console.log(b.value);
},
inserted(el,b,v){
console.log(b.value);
},
update(el,b,v){
console.log(b.value);
}
});
new Vue({
el: "#app" ,
data:{
value:0
}
})
<div id="app">
<button #click="value+=1">
inc value
</button>
<template v-count="value">
</template>
<!-- <div v-count="value">
</div> -->
</div>
If the comment on the div is removed, the directive logs the value, but with the template tag directive's hooks are not triggered
Here jsfiddle for the issue
Thanks
The template tag doesn't actually mount anything on its own, so it has no place in the DOM and doesn't bind. In your case, an easy solution is to just put v-count="value" on the button tag. If there is a more specialized need for this directive and you're just giving us placeholder code, putting it on a SPAN or DIV will make more sense than a template anyway.

VueJS - usage of v-html attribute not working

In my case, I am replacing a link on top of paragraph element using v-html
Please find the code snippet as follows
<p v-html="websiteHTML"></p>
where websiteHTML contains: <a v-bind:href="google.com/">Google</a>
The <p> tag is being rendered with Google but doesn't have hyperlink to navigate to https://www.google.com/
Could you please help in finding the error?
The HTML string you include in your variable should just be HTML, not Vue template code. When you tried including vue template directives, the framework wrote the anchor tag into the DOM with the literal attribute "v-bind:href" instead of the desired "href":
new Vue({
el: '#app',
data: {
websiteHTMLNo: '<a v-bind:href="https://google.com/">Google</a>', // <-- won't work
websiteHTMLYes: 'Google' // <-- do this instead
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p v-html="websiteHTMLNo"></p>
<p v-html="websiteHTMLYes"></p>
</div>
(If you actually do need to inject template code instead of plain HTML, you need to use Vue.compile instead of v-html to parse it.)
if you want to pass a var inside your link.
const url: string = 'https://google.fr/'
const html: string = `Google`
<p v-html="html"></p>

How to bind v-model from input in one div to another div or component

I have my input field in one div, and will have label in another div (as sidebar in my application). I want to update label in sidebar, as I type in input on first div.
I am happy to create second div a component if that's the way. I was reading online, and it was said we could use props to pass data to component. But I am not able to link input field to component. Please find my code as below:
var app = new Vue({
el: '#div1',
data: {
message: ''
}
})
Vue.component('testp', {
props: ['message'],
template: '<p>Message is: {{ message }}</p>'
})
var div2 = new Vue({
el: '#div2'
});
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="div1">
<input v-model="message" placeholder="edit me">
</div>
<div id="div2">
<testp></testp>
</div>
</body>
</html>
As Pointed in Comment You have no reason to have two separate Vue instance and the First Answer is correct. But in some cases where you really need to have multiple Vue instances, you can actually use them in the following manner.
var app = new Vue({
el: '#div1',
data: {
message: ''
}
})
Vue.component('testp', {
props: ['message'],
template: '<p>Message is: {{ message }}</p>'
})
var div2 = new Vue({
el: '#div2',
computed: {
newMessage() {
return app.message;
}
},
});
Html
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="div1">
<input v-model="message" placeholder="edit me">
</div>
<div id="div2">
<testp :message="newMessage"></testp>
</div>
</body>
</html>
Please observe the computed value newMessage is actually getting its value form a different Vue instance (app) and it is also reactive. Therefore whenever the value in first Vue instance changes, it is updated in another Vue instance.
Codepen: https://codepen.io/ashwinbande/pen/xMgQQz
Like I have pointed out in my comments, there is no reason for you to use two separate Vue instances. What you can do is simply wrap everything within an app container, e.g. <div id="#app">, and then instantiate your VueJS instance on that element instead.
Then, you can use v-bind:message="message" on the <testp> component to pass in the message from the parent. In this sense #div1 and #div2 are used entirely for markup/decorative purposes and are not used as VueJS app containers in your code.
Vue.component('testp', {
props: ['message'],
template: '<p>Message is: {{ message }}</p>'
});
var app = new Vue({
el: '#app',
data: {
message: ''
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<div id="div1">
<input v-model="message" placeholder="edit me">
</div>
<div id="div2">
<testp v-bind:message="message"></testp>
</div>
</div>

Is it possible to render two adjacent VueJS components?

I have created two custom VueJS components and I would like to place them adjacent to one another like so:
<div id="app">
<x-component />
<y-component />
</div>
...
new Vue({
el: '#app',
components: {
'x-component': { template: '<div>component x</div>' },
'y-component': { template: '<div>component y</div>' }
}
});
When I do this, only the first component is rendered. Is this a bug in VueJS or am I doing something wrong? It seems like this should be possible.
When I change it as follows, it works:
<div id="app">
<div>
<x-component />
</div>
<div>
<y-component />
</div>
</div>
Reproductions below:
Not working:
https://jsfiddle.net/mquqonuq/1/
Working:
https://jsfiddle.net/mquqonuq/2/
I can't remember right now if it's an html spec issue but custom web elements need to be a two tag closed system, not a self closed single element.
Try:
<div id="app">
<x-component></x-component>
<y-component></y-component>
</div>
Which works.
EDIT:
if you look at google's web components primer it lists
3. Custom elements cannot be self-closing because HTML only allows a few elements to be self-closing. Always write a closing tag (<app-drawer></app-drawer>).

Vue.js: initialize the data object with data from the page or from v-text directive

So I'm just starting to play with Vue.js and I would like to know if there is a nice way to initialize the data object with html tags content from the page.
Basically I have a page that displays information and I would like to turn it into a tiny Vue application to avoid having a separated edit page.
So I added the form with 2 way binding which submits the values via ajax.
The thing is I really want to avoid Flash Of Uncompiled Content, but then I feel like I have to duplicate all my data, once in the html tag, once in the data object.
<div id="app">
<span v-text="prop1">This is filled by the backend</span>
<input v-model="prop1" type="text" v-cloak />
</div>
<script>
new Vue({
el: "#app",
data: {prop1: "This is filled by the backend..again"} // << Can I avoid this?
});
</script>
Could I tell Vue to get the data from the html tags since it's already there?
Thanks!
You are looking for props
Your html element would look something like
<custom-element dataToPass="dataFromHtml"></custom-element>.
Then you can access it in your vue instance via this.dataToPass.
Have a read through the documentation, there is a difference if you pass a string or an expression (from another vue instance for example).
In your example:
<div id="app">
<span prop1="{ backendVariable}" v-text="prop1"></span>
<input v-model="prop1" type="text" v-cloak />
</div>
<script>
new Vue({
el: "#app",
props: ['prop1']
});
</script>
```