I'm trying to render the list with vue.js. The data has come from api call.
List rendering is ok, until I try to add data-feature_id="#{{searched_feature.id}}" in li tag.
When I add it, I got an error:
[Vue warn]: Error compiling template:......
<div class="search_feature_select">
<ul>
<li v-for="searched_feature in searched_features" data-feature_id="#{{searched_feature.id}}" #click="add_to_features_list">
#{{searched_feature.name}}
</li>
</ul>
</div>
How can I put searched_feature.id in data-feature_id attribute?
You need to add : before the attribute
<div class="search_feature_select">
<ul>
<li v-for="searched_feature in searched_features" :data-feature_id="searched_feature.id" #click="add_to_features_list">
{{searched_feature.name}}
</li>
</ul>
</div>
if you wish to add the '#' in front of the data-feature_id attribute:
<div class="search_feature_select">
<ul>
<li v-for="searched_feature in searched_features" :data-feature_id="'#' + searched_feature.id" #click="add_to_features_list">
{{searched_feature.name}}
</li>
</ul>
</div>
https://v2.vuejs.org/v2/guide/list.html coughcough*
var app = new Vue({
el: "#app",
data: {
searched_features: [
{
id: 1,
name: "One"
},
{
id: 2,
name: "Two"
},
{
id: 3,
name: "Three"
}
]
},
methods: {
add_to_features_list(){}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="search_feature_select">
<ul>
<li v-for="searched_feature in searched_features" :data-feature_id="searched_feature.id" #click="add_to_features_list">
#{{ searched_feature.name }}
</li>
</ul>
</div>
</div>
Add 'v-bind:' prefix of shorthand ':' before attribute to bind dynamic data.
<div class="search_feature_select">
<ul>
<li v-for="searched_feature in searched_features"
:data-feature_id="searched_feature.id"
#click="add_to_features_list">
{{searched_feature.name}}
</li>
</ul>
</div>
See more https://v2.vuejs.org/v2/api/#v-bind
Related
In a Vue-component, I have a menu like this:
<ul class="menu-outer-wrapper">
<li>Foo 1</li>
<li class="has-children">
Foo 2
<ul>
<li>Child 1</li>
<li>Child 2</li>
<li>Child 3</li>
</ul>
</li>
<li>Foo 5</li>
<li class="has-children">
Foo 6
<ul>
<li>Child 1</li>
<li>Child 2</li>
</ul>
</li>
<li>Foo 7</li>
<li>Foo 8</li>
</ul>
And I would like to add the class hovered to the li.has-children-elements upon hover (mouseenter) (to be able to make some nicer animations for the children of that dropdown. And remove that class on mouseleave.
I know that there are options to do this with pure CSS, - but controlling delays and soft fade-in's are a pain (and become very messy very fast, without adding some classes).
I imagined doing something like this:
...
mounted(){
let liWithChildren = document.querySelectorAll( '.menu-outer-wrapper > li.has-children' );
liWithChildren.forEach( (event, window) => {
// Somehow add the class to the hovered element here.
// But I don't know how. Or if it's a good/bad idea (performance-wise).
}
}
But is that the way to go? And can I do it without using data (since the menu is dynamically generated by a CMS-system.
Update 1
I'm trying to keep my markdown readable. So I would like to avoid something like this:
<ul class="menu-outer-wrapper">
<li :class="[ { 'hovered' : someVar } ]">
Foo 1
</li>
<li :class="[ { 'hovered' : someVar }, 'has-children' ]">
Foo 2
<ul>
<li>Child 1</li>
<li>Child 2</li>
<li>Child 3</li>
</ul>
</li>
<li :class="[ { 'hovered' : someVar } ]">
Foo 2
</li>
...
...
...
Both since it won't gel with the dynamically generated menu.
And also since it add a lot of noise to the markdown.
Update 2
I simplified the example, to make it easier to digest. But due to the comments I figured I would elaborate on the dynamic generated menu. I'm making it something like this:
<nav id="secondary-menu" v-if="secondaryMenu">
<ul>
<li
:class="[ { 'has-children': r.children } ]"
v-for="(r, r_key, r_index) in secondaryMenu">
<a :href="r.url" :title="r.title">
{{ r.title }}
</a>
<ul class="children" v-if="r.children">
<li v-for="(c1, c1_key, c1_index) in r.children">
<a :href="c1.url" :title="c1.title">
{{ c1.title }}
</a>
</li>
</ul>
</li>
</ul>
</nav>
You just need the #mouseenter and #mouseleave events. All you need to do is listen for the appropriate events on all list-items that could have children, then perform your class addition (or removal) if the target element has the class of "has-children". Here's how I would do it:
<template>
<nav id="secondary-menu" v-if="secondaryMenu">
<ul>
<li
:class="[{ 'has-children': r.children }]"
v-for="(r, r_key, r_index) in secondaryMenu"
:key="`${r_key}-${r_index}`"
#mouseenter="addClass"
#mouseleave="removeClass"
>
<a :href="r.url" :title="r.title">
{{ r.title }}
</a>
<ul class="children" v-if="r.children">
<li
v-for="(c1, c1_key, c1_index) in r.children"
:key="`${c1_key}-${c1_index}`"
>
<a :href="c1.url" :title="c1.title">
{{ c1.title }}
</a>
</li>
</ul>
</li>
</ul>
</nav>
</template>
<script>
export default {
name: "HoverNav",
props: {
secondaryMenu: {
type: Array,
required: true,
},
},
methods: {
addClass: function (e) {
if (e.target.classList.contains("has-children")) {
e.target.classList.add("hovered");
}
},
removeClass: function (e) {
if (e.target.classList.contains("has-children")) {
e.target.classList.remove("hovered");
}
},
},
};
</script>
Here's a very unaesthetic sandbox of this in action. Let me know if this works for you :)
https://codesandbox.io/s/headless-brook-ysq97?file=/src/components/HoverNav.vue:0-1169
I need to have the possibility to print out a possible infinite deep array-structure into a list. Here's the code from a modified AngularJS-example where I have added some more deep children in the array. How can I print child of child and even its children as well? Is there a way I can get it to repeat forever as long as there is more children?
HTML
<div ng-app>
<div ng-controller="TodoCtrl">
<ul>
<li ng-repeat="todo in todos">
<span>{{todo.text}}</span>
<ul>
<li ng-repeat="child in todo.children">
<span>{{child.text}}</span>
<!-- What about the next one -->
</li>
</ul>
</li>
</ul>
</div>
</div>
JS
function TodoCtrl($scope) {
$scope.todos = [{
text: 'root 1',
children: [{
text: 'child of root 1',
children: [{
text: 'child of child',
children: []
}]
}]
}, {
text: 'root 2',
children: []
}];
}
Fiddle: https://jsfiddle.net/U3pVM/25866/
You can use the view recursively this way:
<script type="text/ng-template" id="todo.html">
<div>
<div>{{ todo.text }}</div>
<ul>
<li ng-repeat="todo in todo.children" ng-include="'todo.html'"></li>
</ul>
</div>
</script>
<div ng-controller="MyController">
<ul>
<li ng-repeat="todo in todos" ng-include="'todo.html'"></li>
</ul>
</div>
Here the DEMO based on your sample data.
I have following (json) object:
[
{
name: "Foo",
children: [{
name: "bar",
children:[{
...
}]
}]
}
]
There can be any number of children/objects in any level. Now I want to get following HTML Code:
<ul>
<li>Foo</li>
<li>
<ul>
<li>Bar</li>
</ul>
</li>
<ul>
But of course there could be 10 or more levels with 20 or more children per level.
Is there any way to do that? Thank you very much!
this should work, just replace json array with your data
<script type="text/ng-template" id="nodes_renderer.html">
{{node.name}}
<ul ng-model="node.children" ng-class="{hidden: collapsed}">
<li ng-repeat="node in node.children" ng-include="'nodes_renderer.html'">
</li>
</ul>
</script>
<div data-drag-enabled="false">
<ul>
<li ng-repeat="node in #*JSON ARRAY*#" ng-include="'nodes_renderer.html'">
</li>
</ul>
</div>
View live code:
Angular JS
How in the world do I properly loop through nested key value pairs and properly output them like below?
View I want is a tree like so
-touts
-classes
-col-12
-col-md-12
-col-lg-12
Currently the view is:
touts
{"classes":["col-12","col-md-12","col-lg-12"]}
JS:
var currentApp = angular.module('currentApp', []);
currentApp.controller('ACtrl', function($scope){
$scope.templates = {
'touts' : [
{
'classes' : ['col-12', 'col-md-12', 'col-lg-12' ]
}
]
};
});
HTML:
<div ng-app="currentApp">
<div ng-controller="ACtrl">
<ul ng-repeat="(key, prop) in templates">
<li>{{key}}</li>
<li>
<ul ng-repeat="class in templates[key]">
<li>{{class}}</li>
</ul>
</li>
</ul>
</div>
</div>
You are pretty close, I updated the fiddle. http://jsfiddle.net/y9wj6/9/
<ul ng-repeat="(key, prop) in templates">
<li>{{key}}</li>
<ul ng-repeat="val in prop">
<ul ng-repeat="(o, values) in val">
<li>{{o}}</li>
<ul ng-repeat="i in values">
<li>{{i}}</li>
</ul
</ul>
</ul>
</ul>
You must think gradually.
templates = {'touts' : [{'classes' : ['col-12', 'col-md-12', 'col-lg-12' ] }]};
// key = 'touts'
// props = [{'classes' : ['col-12', 'col-md-12', 'col-lg-12' ] }]
// props[0] = {'classes' : ['col-12', 'col-md-12', 'col-lg-12' ] }
// classkey = 'classes'
// classprop = ['col-12', 'col-md-12', 'col-lg-12' ]
// and print classprop by ng-repeat
So you can try this:
<div ng-app="currentApp">
<div ng-controller="ACtrl">
<ul ng-repeat="(key, props) in templates">
<li>{{key}}</li>
<li>
<ul ng-repeat="(classkey, classprop) in props">
<li>{{classkey}}</li>
<li>
<ul>
<li ng-repeat="class in classprop">
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
So this is pretty old question, however if you modified the object a bit (swap the array types for objects) the following template should work just fine.
angular.module('init', [])
.controller('test', ['$scope', function($scope) {
$scope.templates = {
'touts': {
'classes': {
'col-12': {},
'col-md-12': {},
'col-lg-12': {}
}
}
};
}]);
ul {
list-style: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<div ng-app="init" ng-controller="test">
<script type="text/ng-template" id="recursive_item.html">
{{key}}
<ul>
<li ng-repeat="(key, prop) in prop" ng-include="'recursive_item.html'"></li>
</ul>
</script>
<ul>
<li ng-repeat="(key, prop) in templates" ng-include="'recursive_item.html'"></li>
</ul>
</div>
Using jQuery templates is easy for some simple data structures.
<script type="jquery/x-jquery-tmpl" id="myTemplate">
<li> ${Element} </li>
</script>
var elements = [
{ Element: "Hydrogen" },
{ Element: "Oxygen" },
{ Element: "Nitrogen" }
];
$("#elementsPlaceholder").replaceWith($("#myTemplate").tmpl(elements));
But if I need a template for more complex data? Something like:
<script type="jquery/x-jquery-tmpl" id="myTemplate">
<div> ${Molecule} </div>
consists of:
<ul>
<li> ${Element} </li>
</ul>
</script>
How can apply data to that? Is it possible? Could you show me an example?
<ul>
<li> ${Element} </li>
</ul>
should use {{each}}
<ul>
{{each Elements}}<li>${$value.Element}</li>
</ul>
and then you pass in both the molecule and the elements
$("#elementsPlaceholder").replaceWith($("#myTemplate").tmpl({
Molecule: ...
Elements: [{ Element: "Hydrogen" }, ...]
}))