Rivets.js iterating over collection - javascript

I was trying to perform iteration binding in Rivets.js as described in the documentation. However it seems that no binding occurs.
The template is defined as follows:
<section id="rivets">
<ul>
<li data-each-todo="list.todos">
<input type="checkbox" data-checked="todo.done">
<span data-text="todo.summary"></span>
</li>
<ul>
</section>
The binding is performed by:
var model = {
list: {
todos: [
{ done: true, summary: "Todo 1" },
{ done: false, summary: "Todo 2" }
]
}
}
rivets.bind(document.getElementById('rivets'), model)
I have created a fiddle for this issue. What am I missing?

My bad - the first paragraph of Rivets.js documentation made me use wrong name of Rivets.js attributes (data- instead of rv-).

Related

JS Tree Context Menu Plugin

Initially my JS Tree is
<div id="jstree">
<ul>
<li>Name=
<ul>
<li>Deepanshu</li>
</ul>
</li>
</ul>
</div>
If I edit the name field from Deepanshu to some numeric value, on clicking a submit button, a rest api call happens (which essentially returns the same html back with a pop up saying invalid value). In the html that is returned by the rest call, the js tree is the same as it was before hitting the rest call. Now, if I right click on the node Name or the node Deepanshu either to Edit, Delete, Create new node, etc. the context menu doesn’t appear.
Javascript which I am using is
<script>
$(function () {
$('#jstree').jstree({
"core" : {
"check_callback" : true
},
"plugins" : [
"state", "types", "contextmenu"
]
});
$('#jstree').on('changed_jstree', function (e, data) {
console.log(data.selected);
});
});
</script>
It would be great if someone can help me out with this.
Check your html filed.. An example usage for html filed
<div id="plugins2" class="demo plugin-demo">
<ul>
<li data-jstree='{"opened":true}'>Root node
<ul>
<li>Context click me</li>
</ul>
</li>
</ul>
After, create your JSTree
<script>
$(function () {
$("#plugins2")
.jstree({
"core" : {
'force_text' : true,
"check_callback" : true
},
"plugins" : [ "contextmenu" ]
});
});
</script>
Keep in mind; when you use JSTree be careful for id fields

Checkbox form array data Vue 2

I have a checkbox list which is generated using a for loop that consists of an id and a name:
Data:
yards[{id:1,name:'test'}] etc
HTML:
<ul class="checkbox-list">
<template v-for="(yard, index) in yards">
<li>
<input type="checkbox"
v-bind:id="'yardlist_'+yard.name"
v-bind:value="yard.id"
v-model="newSchedule.yards.id">
<label v-bind:for="'yardlist_'+yard.name">{{ yard.name }}</label>
</li>
<li>
<input type="text"
class="form-control"
placeholder="Yard notes..."
v-model="newSchedule.yards.notes">
</li>
</template>
</ul>
I want to save the selected checkbox with the id and notes field in an array:
newSchedule: {
due_at: '',
notes: '',
users: [],
yards: [{id:'',notes:'']
}
I have tried using the index from the yards array: newSchedule.yards[index].notes but am getting the following error "TypeError: undefined is not an object (evaluating 'newSchedule.yards[index].id')"
Any ideas how I can achieve this?
** Update **
Here is a basic fiddle of what I am wanting to achieve:
https://jsfiddle.net/j7mxe5p2/13/
I think you are trying to mix the old jQuery or javascript way of doing things with Vue framework. You should not have to set id on <input> elements to capture or set its value.
The correct way to do this is as follows:
new Vue({
el: '#app',
data: function() {
return {
yards: [
{id: 1, name: 'test', selected: true},
{id: 2,name: 'test 2', selected: false},
{id: 3,name: 'test 3', selected: false},
{id: 4,name: 'test 4', selected: true}
]
};
},
template: `
<div class="list-of-yards"> <!-- You cannot use v-for on the top-level element -->
<label for="jack" v-for="yard in yards">
<input type="checkbox" v-model="yard.selected"> {{yard.name}}
</label>
</div>
`,
});
Here is a jsFiddle of the above code: https://jsfiddle.net/z48thf9a/
Things to note:
You cannot use v-for on the template tag itself
You cannot use v-for on the top-level element just inside template. The template should contain one and only enclosing element, typically a <div>
There is no need to set id on input elements. You need to use v-model for your model-view bindings
If you still have issues, please provide a jsFiddle to debug further.
Edited after comment #1 and #2:
My above response is focused more on constructing the Vue component and rendering the list with proper binding to the checkboxes.
To get the checked items into a separate array, you can use a computed property in the same component to run through the original array this.yards and create a new array of selected items only.
Here is the jsFiddle for capturing the checked values: https://jsfiddle.net/z48thf9a/1/
You may modify the above to capture only the id part, and rename selectedYards to newSchedule or whatever your app requires.
I am not sure if I understood your question correctly, and if this solves your issue. Can you please provide more code samples?

How to make angular empty filters match undefined and null values?

I've found a problem while typing a filter and then remove it, the collection keeps being filtered and not showing the items with undefined or null values in the filtered term.
An example code:
<div ng-app="App" ng-controller="AppController as app">
<p>
Filters
</p>
Name: <input ng-model="listFilters.name" type="text"/>
<br/>
Short Description: <input ng-model="listFilters.shortDescription" type="text"/>
<ul>
<li ng-repeat="person in app.persons | filter:{name: listFilters.name, shortDescription: listFilters.shortDescription}">
<p>{{person.name}}</p>
</li>
</ul>
</div>
The angular code:
angular.module('App', []);
angular.module('App').controller('AppController', AppController);
function AppController() {
var ctrl = this;
ctrl.persons = [
{
name: 'Bill',
shortDescription: null
},
{
name: 'Sally',
shortDescription: 'A girl'
},
{
name: 'Jhon',
},
];
}
A working fiddle: https://jsfiddle.net/89pkcww2/
Steps to see the problem I'm talking about:
Filter by name, the list is filtered.
Erase the filter, see how the list is again displayed (Bill, Sally, Jhon).
Filter by description, the list is filtered.
Erase the filter, only the second value of the collection is displayed (Sally) the ones with undefined or nulls aren't. It's filtering by "empty string".
I guess this is a default behavior in Angular filters but... is there a way to change it? Do I have to make my own filter?
I want to filter by both properties separately, the collection | filter: filter.var does not serve this purpose.
Nor this is the same as filtering to show only not null values, it's closer to the opposite...
shortDescription: null , it doesnt mean '' , null != '' , so when you delete the text from the 'short description' it doesnt show 'Bill' item.
on third item there is not shortDescription at all so the ng-model="listFilters.shortDescription" cant bind to the property.
only 'Sally' item works ok because the ng-model can bind to the property.
Update your li html to something like this:
<li ng-repeat="person in app.persons | filter:listFilters.name">
Here is the updated fiddle: https://jsfiddle.net/89pkcww2/1/

Handlebars #each fails with one item

I have a handlebars template that uses each statements, one nested inside the other.
It works just fine, until the inner each comes across an item in the data set that only has one item, in which case it doesn't output anything.
Here's my template:
<div class="container">
{{#each stories.story}}
<div class="story">
<h1 class="mask">
<span>
{{copy.heading}}
</span>
</h1>
<ul class="story-copy">
{{#each copy.body.text}}
<li class="mask">
<span>{{this}}</span>
</li>
{{/each}}
</ul>
</div>
{{/each}}
</div>
The interesting thing, as I said, is that when the ul is being output when copy.body.text has more than one text node, it works. If there is only ONE, it comes out empty.
There's gotta be something I'm missing. Can anyone help?
couldn't reproduce your bug.
can you post your data?
this one works for me: http://jsfiddle.net/Schniz/7v0qawbd/
var data = {
stories: {
story: [{
copy: {
heading: "hello",
body: {
text: [
"Hey"
]
}
}
}]
}
};
yet, even though I don't really know how your data looks, I think looks like your template should be kinda different: http://jsfiddle.net/Schniz/Ly8uh2u1/ for using with data that looks like:
var data = {
stories: [{
copy: {
heading: "hello",
body: [
"Hey"
]
}
}]
};

Dealing with an empty list in mustache.js

I'm using mustache.js to render a template in javascript. I'd like to check if a list is empty or not to hide the <h2> tag in the following example. Is this possible or is mustache.js too logic-less?
This is the template:
<h2>Persons:</h2>
<ul>
{{#persons}}
{{name}}
{{/persons}}
</ul>
and this is the data:
{
"persons":[
{"name": "max"},
{"name": "tom"}
]
}
After struggling for half a day with this problem, I've finally found an easy solution!
Don't check for the list, but check if its first item is not empty!
Template:
{{#persons.0}}
<h2>Persons:</h2>
<ul>
{{#persons}}
<li>{{name}}</li>
{{/persons}}
</ul>
{{/persons.0}}
{{^persons.0}}No persons{{/persons.0}}
Data:
{
"persons":[
{"name": "max"},
{"name": "tom"}
]
}
Output:
<h2>Persons:</h2>
<ul>
<li>max</li>
<li>tom</li>
</ul>
Data:
{
"persons": []
}
Output:
"No Persons"
You could use persons.length. If it is a truthy value (i.e. greater than 0) then the block will be rendered.
{{#persons.length}}
<h2>Persons:</h2>
<ul>
{{#persons}}
<li>{{name}}</li>
{{/persons}}
</ul>
{{/persons.length}}
To keep your template logic-less, you can make this check before rendering the template:
// assuming you get the JSON converted into an object
var data = {
persons: [
{name: "max"}
, {name: "tom"}
]
};
data.hasPersons = (data.persons.length > 0);
Then your template will look like this:
<h2>Persons:</h2>
{{#hasPersons}}
<ul>
{{#persons}}
<li>{{name}}</li>
{{/persons}}
</ul>
{{/hasPersons}}
Use handlebars instead. It's a superset of Mustache which gives you that little bit more power that you need. The mustache community asked for this feature but the maintainer refuses to put it in.
In javascript you can check with {{#names.length}}{{/names.length}} or with {{#names.0}}
If you're outside of javascript (e.g. in pystache or Scalate), you're out of luck. The only solution then is to introduce a separate boolean, or nest your array in an object which you avoid entirely if you have an empty array, like maxbeatty suggested.

Categories

Resources