Vue dynamic html - won't to parse vue data object - vuejs2

I have sample code written in Vue:
template: `
<table>
<tbody>
<tr v-html="tableHTMLContent"></tr>
</tbody>
</table>`,
data() {
this.tableHTMLContent: '',
this.myTextName: 'aaaa'
},
methods: {
addSampleCode() {
this.tableHTMLContent = '<p> {{ myTextName }} </p>'
}
}
The problem is with parsing {{ myTextName }} tag. Html is injected correctly, but Vue won't to parse myTextName variable. Vue doesn't display aaaa value.
What I have to do to parse Vue tags like {{ }} and others tags like v-for, v-if and so on.

To render data values together with template code within a method you can use Vue.compile( ... )
See this link:
https://v2.vuejs.org/v2/api/#Vue-compile
Usage Example:
var res = Vue.compile('<div><span>{{ msg }}</span></div>')
new Vue({
data: {
msg: 'hello'
},
render: res.render,
staticRenderFns: res.staticRenderFns
})

Related

Inject symfony variables with array of Objects to a vue.js component from a twig template

I am using symfony5 and would like to integrate vue.js in one of my twig template views. I need to be able to pass 3 different Objects to vue.js. I have to pass on multiple Arrays which store normally multiple Objects to a vue component so I have done the following after installing vue.js
How would I access groups in the vue component and am I doing it the right way injecting the array to my component? do I have to use $jsonContent = $serializer->serialize($groups, 'json') in the controller or can I leave the array as it is?
// assets/js/app.js
import Vue from 'vue';
import Example from './components/Example'
new Vue({
el: '#app',
components: {Example}
});
// assets/js/components/Example.vue
<template>
<div>
<h2 class="center">My Application</h2>
<div v-text="message"></div>
<pre>{{ groups }}</pre>
<ul>
<li :key="group.id" v-for="group in groups">{{ group }}</li>
</ul>
</div>
<script>
export default {
data() {
return {
message: "A list of groups",
groups: [],
};
},
mounted() {
this.groups = this.$el.attributes['groups'].value;
console.log(this.groups);
}
};
</script>
<style>
.center {
text-align: center;
}
</style>
in my twig view I have the following
<div ref="groups" v-bind:groups="{{ groups2|json_encode }}"></div>
<div id="app">
<example></example>
</div>
groups normally looks like this:
array:5 [▼
0 => App\Document\Group {#630 ▶}
1 => App\Document\Group {#627 ▶}
2 => App\Document\Group {#638 ▶}
3 => App\Document\Group {#641 ▶}
4 => App\Document\Group {#644 ▶}
]
so I used a serializer in the controller
'groups2' => $jsonContent = $serializer->serialize($groups, 'json'),
The answer above is correct, though it could be more explicit. Render the data inside a script tag, set it to 'application/json', then make your component query the dom and parse the data when it initializes with the created lifecycle hook.
PageController.php:
return $this->render('page.html.twig', [
'array' => json_encode([
'data1' => $values1,
'data2' => $values2
]),
'title' => 'Title'
]);
Twig Template:
<script id="pageData" type="application/json">
{
"array": {{ array | raw }},
"title": "{{ title }}"
}
<script>
Component.vue:
import Vue from 'vue';
import Example from './components/Example'
new Vue({
el: '#app',
data: { array: [], title: '' },
components: {Example},
created() {
this.data = JSON.parse(document.getElementById('pageData').innerHTML);
}
});
Note that you might need to update your state with Vue.set(this.data, 'array', []) if you just want to update part of the state in a reactive way.
You cannot use vue syntax in your twig file. The simple way to pass your groups in vue file is to put your groups, that you have in twig files, like that:
<script type="text/javascript">
var groups = {{ groups|json_encode()|raw }};
</script>
and than, you can get groups object from window js object, may be there are other solutions

vuejs-paginator example html markup

I have a pretty daft question re: vuejs-paginator but I am having a hard time getting to run this example (I am a backend dev here).
So, I have on my head:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuejs-paginator/2.0.0/vuejs-paginator.js"></script>
Then as described in the page, I have:
<script>
new Vue({
el: '#app',
data () {
return {
// The resource variable
animals: [],
// Here you define the url of your paginated API
resource_url: 'http://hootlex.github.io/vuejs-paginator/samples/animals1.json'
}
},
components: {
VPaginator: VuePaginator
},
methods: {
updateResource(data){
this.animals = data
}
}
});
</script>
Now, what the F I should have in my HTML, I have no clue, and the author seems to say, I use:
<v-paginator resource_url="api/animals" #update="updateResource"></v-paginator>
but, this I think is just for the pagination. What shoud the app element contain and where is it? The docs dont seem to show this? he author then shows some random markup:
<ul>
<li v-for="animal in animals">
{{ animal.name }}
</li>
</ul>
Where should this go? Should I have an app div element?
You can add content to your app by adding it to the template key:
<script>
new Vue({
el: '#app',
data () {
return {
// The resource variable
animals: [],
// Here you define the url of your paginated API
resource_url: 'http://hootlex.github.io/vuejs-paginator/samples/animals1.json'
}
},
components: {
VPaginator: VuePaginator
},
methods: {
updateResource(data){
this.animals = data
}
},
template: `
<div>
<ul>
<li v-for="animal in animals">
{{ animal.name }}
</li>
</ul>
<v-paginator :resource_url="resource_url" #update="updateResource"></v-paginator>
</div>
`
});
</script>
Something like that.
You also need an initial <div id="app"></div> in your html. This is the element where Vue will mount the app and load the content.
EDIT
The plugin uses this.$http which requires some kind of dependency that it doesn't specify.
I have made an alteration in the following codepen and it works properly now:
https://codesandbox.io/s/competent-dream-zngzt

vue-filter doesn't work with v-html

This problem has few solutions but nothing worked for me. I am using a package called vue-filter and I want to use nl2br filter. When I try to use it in my html like this
<p style="padding: 10px;font-size: 17px;" v-html="$options.filters.nl2br(opDesc.description)"></p>
It gives me the following error
TypeError: _vm.$options.filters.nl2br is not a function
Here is the package github link https://github.com/wy-ei/vue-filter#nl2br
You can use
v-html="$options.filters.FILTERNAME(args)" or
:inner-html.prop="args | FILTERNAME".
See demo below.
Vue.filter('upper', function (value) {
return value.toUpperCase();
})
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p v-html="$options.filters.upper(message)"></p>
<p :inner-html.prop="message | upper"></p>
</div>
Its ok. Filters does not works in v-html directive. Only in mustache interpolations and v-bind directive.
Use computed property instead:
<any-tag v-html="filtered" />
In component, use something like this:
computed: {
filtered () {
return this.nl2br(this.rawHtml)
}
},
methods: {
nl2br (source) {
var filtered = //Filter logic here
return filtered
}
}

Vue the same component tag name will impact by other data source

I design a CMS for content editing, and I have a template_id list for user to select what kind of template he/she wants.
my code like below:
CodePen
https://codepen.io/Aircon/pen/NjeMwG/
HTML
<div id="app">
<section v-for="s, index in sections">
<h3>Section {{ index }} </h3>
<select #change="templateChange(index)" v-model="s.selected_option">
<option value="">-----</option>
<option v-for="t, key in templates" :value="key">{{ key }}</option>
</select>
<my-component></my-component>
</section>
</div>
JAVASCRIPT
var sections = [
{
selected_option: ''
},
{
selected_option: ''
}
];
var templates = {
template01: {
html: "<p>TEMPLATE01</p>"
},
template02: {
html: "<p>TEMPLATE02</p>"
}
};
var vm = new Vue({
el: "#app",
data: {
sections: sections,
templates: templates
},
methods: {
templateChange(index) {
console.log("option:" + sections[index].selected_option);
Vue.component("my-component", {
template: templates[sections[index].selected_option].html
});
}
}
});
The problem is
if i have more then one section, component will be impact by others selection, how can i fix it ?
Changing a component's template within another component is going to change the definition globally and is bad practice.
You should initially register two components, one for each template:
Vue.component("my-component-1", { template: "<p>TEMPLATE01</p>" });
Vue.component("my-component-2", { template: "<p>TEMPLATE02</p>" });
Change your Vue instance's data properties to include the two component names instead of the templates:
data: {
sections: sections,
components: ['my-component-1', 'my-component-2']
},
Change your v-for to loop through the new components array instead:
<option v-for="component in components" :value="component">{{ component }}</option>
And, finally, change the displayed component to be a dynamic component using the :is directive to bind the type of component to the selected option:
<component :is="s.selected_option"></component>
Here's a working codepen.

Vue passing data to child component

I have an issue where I'm trying to pass an object 'through' one component, which is the overall layout, to child components which sit inside it. I've made a simplified example where I basically have a <ul></ul> template and an <li></li> template.
I seem to be losing the reference for each one by the time they are created. When I create them, I get the error:
vue.js:1023 [Vue warn]: Error when evaluating expression "model.id":
TypeError: Cannot read property 'id' of undefined (found in component:
<demo-list-item>)
What am I doing wrong?
I think I just have a fundamental missing from my knowledge of Vue... I'm really, really new to it and am learning from their website – so this could be a really obvious / silly mistake.
HTML:
<div id="app">
<demo-list></demo-list>
<script id="demo-list-template" type="text/x-template">
<ul>
<demo-list-item v-for="item in items"></demo-list-item>
</ul>
</script>
<script id="demo-list-item-template" type="text/x-template">
<li data-id="{{model.id}}">{{ model.name }}</li>
</script>
</div>
JavaScript:
// define
var DemoList = Vue.extend({
template: '#demo-list-template',
data : function(){
return {
'items' : [
{
'id' : 1,
'name' : 'this'
},
{
'id' : 2,
'name' : 'that'
},
{
'id' : 3,
'name' : 'something'
},
{
'id' : 4,
'name' : 'nothing'
}
]
}
}
});
// List Item
var DemoListItem = Vue.extend({
template : '#demo-list-item-template'
});
// register
Vue.component('demo-list', DemoList);
Vue.component('demo-list-item', DemoListItem);
// create a root instance
var Vue = new Vue({
el: '#app',
});
Demo:
http://codepen.io/EightArmsHQ/pen/vXYWgz
According to the Component props doc, you can pass data to child component like this :
<child name="value"></child>
and
<child :name="value"></child>
for dynamic props
So, in your template, when you loop over items array, you got item object. Just pass it to your child component
<demo-list-item v-for="item in items" :item="item">
Also, in your child component, you have to tell that you attempt to get a prop named item
var DemoListItem = Vue.extend({
template : '#demo-list-item-template',
props: ['item']
});
You can validate props, set default value, etc (see doc)
Now, in your child template, you have access to item property
<li data-id="{{item.id}}">{{ item.name }}</li>