Rivets JS data-show not working - javascript

I am trying to do a simple show/hide using Rivets JS (previously using Aurelia). I thought i had the right code to do the job after looking through various sites however it doesnt seem to be working.
my HTML:
<div id="Payments">
<h1 rv-text="data.title"></h1>
<div class="col-md-4">
<select rv-value="data.selectedVal" class="form-control">
<option value="0" selected></option>
<option rv-each-country="data.countries" rv-value="country.id" rv-text="country.name"></option>
</select>
</div>
<div class="container" style="padding-top:40px;">
<div class="row">
<table class="table .table-responsive table-hover">
<tbody>
<tr rv-each-product="data.products" data-show="data.selectedVal | eq product.id" >
<td rv-text="product.title" ></td>
<td rv-text="product.id"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
my js:
var data = {
title: 'Welcome to Payments',
products: [
{
title: 'MasterCard',
id: 'CH'
},
{
title: 'Visa',
id: 'UK'
},
{
title: 'PayPal',
id: 'US'
},
{
title: 'Cheque',
id: 'UK'
},
{
title: 'Cash',
id: 'US'
}],
countries: [
{
name: 'China',
id: 1
},
{
name: 'USA',
id: 'US'
},
{
name: 'UK',
id: 'UK'
}
],
selectedVal: ''
};
rivets.formatters.eq = function (value, args) {
debugger;
return value === args;
};
rivets.bind(
document.querySelector('#Payments'), // bind to the element with id "candy- shop"
{
data: data // add the data object so we can reference it in our template
});
The List of payment should show or hide based on the selected country.
Any help would be great!
Thanks

Needed to use rv-show and not data-show. Must have read the wrong documentation.

Related

Vue v-for after condition using vuex

While I am trying to create a form I encountered this problem which I don't have any solution.
There is a Vuex data on Vehicles Make and Model of vehicle, now once the make is selected, I want the other form to loop through the selected Make and find other models... something like that.
Here is what I did so far:
cars.js - (vuex module)
const state = {
make: [
{
name: 'Audi',
carid: '1',
models: [
{
modelid: '1.1',
name: 'A7',
},
{
modelid: '1.2',
name: 'A8',
},
],
},
{
name: 'BMW',
carid: '2',
models: [
{
modelid: '2.1',
name: '5 Series',
},
{
modelid: '2.2',
name: '7 Series',
},
],
},
],
}
Cars.vue
<template>
<div class="labelos">
<div class="label-name">
<h4>Car make:</h4>
</div>
<div class="label-body">
<label for="car-make">
<select v-model="selectedType" name="carmake" required>
<option value=""></option>
<option v-for="(cars, index) in cars.make" :key="index" :value="cars.carid">{{ cars.name }}</option>
</select>
</label>
</div>
</div>
<div class="labelos">
<div class="label-name">
<h4>Car model:</h4>
</div>
<div class="label-body">
<label for="car-model">
<select>
<option value=""></option>
<option v-for="(model, index) in cars.make" :key="index" :value="cars.carid">{{ model.carid }}</option>
</select>
</label>
Model:
</div>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'cars',
data() {
return {
selectedType: '',
selectedCity: '',
};
},
methods: {
},
components: {
Headers,
Footers,
},
computed: {
...mapState([
'cities', 'cars',
]),
},
};
</script>
So as you can see on first label I am looping through makes, and once a car make is selected that carid is saved on selectedType, now how is that possible to load second dropdown according to that selection, so if carid 1 is selected, the list will load car models available on given carid (in this example carid 1)
Looking forward to hear from someone, I am stuck here.. I don't know any solution how to do this... this is so far I have done
Cheers
You should create a computed property which returns model options based on the value of the selected make type. Then you can bind to that and it will automatically update whenever the selected make changes:
models() {
if (this.selectedType) {
return this.cars.make.find((car) => car.carid === this.selectedType).models;
}
}
Here's a working example:
const store = new Vuex.Store({
state: {
cars: {
make: [{
name: 'Audi',
carid: '1',
models: [
{ modelid: '1.1', name: 'A7' },
{ modelid: '1.2', name: 'A8' },
]
}, {
name: 'BMW',
carid: '2',
models: [
{ modelid: '2.1', name: '5 Series' },
{ modelid: '2.2', name: '7 Series' }
],
}]
}
}
})
new Vue({
el: '#app',
store,
data() {
return {
selectedType: '',
};
},
computed: {
...Vuex.mapState(['cars']),
models() {
if (this.selectedType) {
return this.cars.make.find((car) => car.carid === this.selectedType).models;
}
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.min.js"></script>
<div id="app">
<h4>Car make:</h4>
<select v-model="selectedType" name="carmake" required>
<option value=""></option>
<option v-for="(cars, index) in cars.make" :key="index" :value="cars.carid">{{ cars.name }}</option>
</select>
<h4>Car model:</h4>
<select>
<option value=""></option>
<option v-for="(model, index) in models" :key="index" :value="model.modelid">{{ model.name }}</option>
</select>
</div>
Working example with your data:
const state = {
make: [
{
name: 'Audi',
carid: '1',
models: [
{modelid: '1.1', name: 'A7'},
{modelid: '1.2', name: 'A8'}
]
}, {
name: 'BMW',
carid: '2',
models: [
{modelid: '2.1', name: '5 Series'},
{modelid: '2.2', name: '7 Series'}
]
}
]
}
new Vue({
el: '#app',
data: {
state: state,
selected: 0
},
computed: {
models () {
var maker = this.state.make.find(m => m.carid === this.selected)
return maker ? maker.models : []
}
}
})
<div id="app">
<select v-model="selected">
<option value="0" selected>Choose maker</option>
<option
v-for="maker in state.make"
:key="maker.carid"
:value="maker.carid"
>{{ maker.name }}</option>
</select>
<br>
<select>
<option value="0" selected>Select model</option>
<option
v-for="model in models"
:key="model.modelid"
:value="model.modelid"
>{{ model.name }}</option>
</select>
</div>
<script src="https://unpkg.com/vue#2.5.3/dist/vue.min.js"></script>
If you can, change 'modelid' to simple integers - 1, 2, etc., at least. And if you can and you know how to do it, change your data structure - divide makers and models to separate arrays/objects.
Here's a plugin for this specific task you're trying to accomplish: vue-dependon.
It hasn't been updated for 1-2years, but I think that you can check its source code and see how it works.
UPDATE:
All you need from the sourcecode is the loadOptions function and the code between L83 and L105.
You can adapt that code to your needs.

How to reinitialize Angular model with nested data?

I've start a little proof of concept this week with Angular Material, and in this POC, I have a table that displays nested data:
<table>
<thead>
<tr>
<th colspan="2">Employee Name</th>
<th>Ovr</th>
<th> </th>
<tr>
<thead>
<tbody ng-repeat="employee in evaluation.employees" >
<tr ng-class-odd="'odd-row'">
<td class="photo"><img src="{{employee.photo}}" /></td>
<td class="name"><span class="firstname">{{employee.firstName}}</span><br/><span class="lastname">{{employee.lastName}}</span></td>
<td class="column-align-center"><span>{{employee.grade}}</span></td>
<td class="column-align-center"><md-button ng-click="toggleAptitudes(employee.id)" class="md-raised md-primary custom-button">+</md-button></td>
</tr>
<tr ng-repeat="skill in employee.skills" ng-show="employee.displayAptitudes">
<td colspan="4" style="padding: 0px 20px 0px 20px;">
<md-slider-container>
<span>{{skill.name}}</span>
<md-slider class="md-primary" flex min="0" max="100" ng-model="skill.value" ng-change="calculateAptitudesGrade(employee.id)" aria-label="skill.name" id="red-slider">
</md-slider>
<md-input-container>
<input flex type="number" ng-model="skill.value" aria-label="skill.title" aria-controls="red-slider">
</md-input-container>
</md-slider-container>
</td>
</tr>
</tbody>
</table>
Snippet from the Controller:
var self = this;
// Mock data...
self.employees = [
{ id: 1, firstName: 'FirstName1', lastName: 'LastName1', photo: 'img/photo1.png', grade: 0, aptitudes: [...], displayAptitudes: false },
{ id: 2, firstName: 'FirstName2', lastName: 'LastName2', photo: 'img/photo2.png', grade: 0, aptitudes: [...], displayAptitudes: false }
];
$scope.calculateAptitudesGrade = function(employeeId) {
// The overall calculation happen here where I collect all the skills values for the employee.
...
};
It's working fine for the first row I modify. I click the toggle button, it shows a list of skills with sliders, I move the slider and the overall calculation works very well.
THE PROBLEM: whenever I choose another employee, the sliders are set visually with the previous values. How to have the sliders set to 0 for each employee?
For your ng-click on the button change it from toggleAptitudes(employee.id) to employee.displayAptitudes = !employee.displayAptitudes
Ok ok ok, I've found the problem!!
Like I says, it is a POC and I did this quick. The problem come from the «Aptitudes» array that I have defined... and reused for every employee defined in the array...
self.aptitudes= [
{ id: 1, title: 'Aptitude 1', value: 0 },
{ id: 2, title: 'Aptitude 2', value: 0 },
{ id: 3, title: 'Aptitude 3', value: 0 }
];
// Mock data...
self.employees = [
{ id: 1, firstName: 'FirstName1', lastName: 'LastName1', photo: 'img/photo1.png', grade: 0, aptitudes: self.aptitudes, displayAptitudes: false },
{ id: 2, firstName: 'FirstName2', lastName: 'LastName2', photo: 'img/photo2.png', grade: 0, aptitudes: self.aptitudes, displayAptitudes: false }
];
Instead of declaring an array, I have create a function that return the array:
function getAptitudes() {
return [
{ id: 1, title: 'Aptitude 1', value: 0 },
{ id: 2, title: 'Aptitude 2', value: 0 },
{ id: 3, title: 'Aptitude 3', value: 0 }
];
}

AngularJS Binding an object

In my controller I have this:
$scope.participants = [
{
name: "Alan",
birthday: new Date("1991/01/21"),
takePart: true,
},
{
name: "Leandro",
birthday: new Date("1991/01/21"),
takePart: true,
},
{
name: "Alejandro",
birthday: new Date("1991/03/21"),
takePart: true,
}
]
And I'm showing them in my View doing this:
<select name="" id="">
<option ng-repeat="p in participants">{{ p.name }}</option>
</select>
I want to show each one information in some place when I select one of them in the select html element. Is there a way to bind the object?
Use ng-options on your select box, and give it a ng-model. When the select is changed the model will hold the object represented by the selected item.
After that just use the model to display
<select ng-model="currentItem"
ng-options="participant.name for participant in participants">
</select>
<div>
{{currentItem.name}}<br/>
{{currentItem.birthday}}<br/>
{{currentItem.takePart}} </div>
</div>
Demo
var app = angular.module("test",[]);
app.controller("Test",function($scope){
$scope.participants = [
{
name: "Alan",
birthday: new Date("1991/01/21"),
takePart: true,
},
{
name: "Leandro",
birthday: new Date("1991/01/21"),
takePart: true,
},
{
name: "Alejandro",
birthday: new Date("1991/03/21"),
takePart: true,
}
];
$scope.currentItem = $scope.participants[0];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="Test">
<select ng-model="currentItem" ng-options="participant.name for participant in participants">
</select>
<div>
{{currentItem.name}}<br/>
{{currentItem.birthday}}<br/>
{{currentItem.takePart}} </div>
</div>
While ng-options is better, this is your way:
HTML:
<select name="" ng-model="test" ng-change="hello()" id="">
<option ng-repeat="p in participants">{{ p.name }}</option>
</select>
<p>{{pt.name}} - {{pt.birthday}} - {{pt.takePart}}</p>
JS:
$scope.participants = [
{
name: "Alan",
birthday: new Date("1991/01/21"),
takePart: true,
},
{
name: "Leandro",
birthday: new Date("1991/01/21"),
takePart: true,
},
{
name: "Alejandro",
birthday: new Date("1991/03/21"),
takePart: true,
}
]
$scope.test=$scope.participants[0].name;
$scope.pt=$scope.participants[0];
$scope.hello = function(){
angular.forEach($scope.participants, function(item){
if(item.name==$scope.test){
$scope.pt = item;
}
})
};
Fiddle Here
(Sorry for the variable names ;))

Filter Data in nested json

My angular controller is following -
how to filter nested data like first row of json-
<script>
var myApp = angular.module('myApp', ['angular.filter']);
function VersionFilterCtrl($scope) {
$scope.limit=6;
$scope.orders = [
{ id:1, customer:[{ name: 'John1', id: 10 },{ name: 'John2', id: 100 }] },
{ id:2, customer: { name: 'William', id: 20 } },
{ id:3, customer: { name: 'John', id: 10 } },
{ id:4, customer: { name: 'William', id: 20 } },
{ id:5, customer: { name: 'Clive', id: 30 } }
];
}
</script>
and my html
<div ng-app="myApp">
<div ng-controller="VersionFilterCtrl">
<input type='text' name='name' ng-model='search.customer.name'>
<input type='text' name='name' ng-model='search.customer.id'>
<li ng-repeat="order in orders| filterBy: ['customer.name']: search.customer.name| filterBy: ['customer.id']: search.customer.id">
{{order.id}}{{order.customer.name}}
</li>
</div>
</div>
JSFIDDLE EXAMPLE
You approached this correctly in how you set up your search models to match the structure of the data you are filtering, i.e. search.customer.name and search.customer.id.
All you need to do is to apply the search object as the filter:
<li ng-repeat="order in orders | filter: search">
{{order.id}} | id: {{order.customer.id}} name: {{order.customer.name}}
</li>
plunker
A few other issues:
There is no filterBy (unless you create your own)
Your first order record has an array of customers - was this intentional? This plunker handles that case

KnockoutJS: Handling Select Boxes. Selecting a default value and removing an existing item

I am having trouble handling checkboxes in Knockout JS.
jsfiddle link: http://jsfiddle.net/wenbert/Xyuhk/72/
Note that I have provided 2 select boxes for each parent (Hero). Each one is using a different way but both are more or less "observing" the same object.
Workflow
Click on a gray box
A box with a blue dotted line should appear containing the items of the Select box.
From here, you can edit the items of the select box.
Fiddle here: http://jsfiddle.net/wenbert/Xyuhk/72/
The Problems
When I remove an item, I am not able to remove it from the Select boxes. Note that I do not want to completely remove it from the object. I just want the current item to be flagged as "isDeleted".
Select A - hides the item but it leaves an empty option in the select box.
Select B - the "ifnot: isDeleted" is not having any effect on the options.
The Question
How do I handle Select Boxes? I have rendered 2 Select Boxes in 2 different ways to try to have the ifnot: isDeleted take effect but none of them are working.
Update: With this setup, how do I do the "selected" value of the select box?
HTML
<button data-bind="click: addHero">Add Hero</button>
<ul data-bind="foreach: heroes">
<li class="parent" data-bind="ifnot: isDeleted, click: $parent.selectHero">
<input class="big-box" type="text" data-bind="value: name" />
<button class="btn-small" data-bind="click: $parent.removeHero">Remove Hero</button>
<br/>
SKILLS:
Select A) <select data-bind="foreach: skills">
<option data-bind="value: name, text: name, ifnot: isDeleted"></option>
</select>
Select B) <select data-bind="options: skills, optionsText: 'name', value: selected_skill.name, ifnot: isDeleted">
</select>
<br/>
<span class="instructions">(Step 1: Click somewhere here)</span>
</li>
</ul>
<div class="edit-panel" data-bind="if: selectedHero">
Edit Skill:<br/>
<div data-bind="with: selectedHero">
<button class="btn-small" data-bind="click: addSkill">Add Skill</button>
<ul data-bind="foreach: skills">
<li data-bind="ifnot: isDeleted">
<button class="btn-small" data-bind="click: $parent.setAsDefaultSkill">Set as default</button>
<input data-bind="value: name" />
<button class="btn-small" data-bind="click: $parent.removeSkill">Remove Skill</button>
</li>
</ul>
<span class="instructions">(Step 2: Remove a Skill, then have a look at the Select Box above.)</span>
</div>
</div>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
Javascript
var initialData = [
{
id: '1',
name: "Batman",
isDelete: false,
selected_skill: {name: "Boxing", isDeleted: false},
skills: [
{ id: '1', name: "Karate", isDeleted: false },
{ id: '2', name: "Boxing", isDeleted: false},
{ id: '6', name: "Sonar", isDeleted: false}
]
},
{
id: '2',
name: "Hulk",
isDelete: false,
skills: [
{ id: '3', name: "MMA", isDeleted: false },
{ id: '4', name: "Rage", isDeleted: false},
{ id: '5', name: "Extra Strength", isDeleted: false}
]
},
];
function Hero(data) {
var self = this;
self.name = ko.observable(data.name);
self.selected_skill= ko.observable(data.selected_skill);
self.skills = ko.observableArray(ko.utils.arrayMap(data.skills, function(i) {
return new Skills(i);
}));
self.addSkill = function() {
self.skills.push(new Skills({name: '---', isDeleted: false}));
}
self.setAsDefaultSkill = function(item) {
self.selected_skill(item);
}
self.isDeleted = ko.observable(data.isDeleted);
self.removeSkill = function(item) {
item.isDeleted(true);
}
}
function Skills(data) {
var self = this;
self.name = ko.observable(data.name);
self.isDeleted = ko.observable(data.isDeleted);
}
function SuperheroViewModel(data) {
var self = this;
self.heroes = ko.observableArray(ko.utils.arrayMap(data, function(i){
return new Hero(i);
}));
self.selectedHero = ko.observable();
self.selectedHero.skills = ko.observableArray();
self.addHero = function() {
self.heroes.push(
new Hero({
name: 'Wolverine',
isDelete: false,
skills: [{name: 'Breathing', isDeleted: false}],
})
);
}
self.selectHero = function(item) {
self.selectedHero(item);
}
self.removeHero= function(item) {
item.isDeleted(true);
}
}
ko.applyBindings(new SuperheroViewModel(initialData ));
​
​
I hope everything is clear.
Any reply will be greatly appreciated.
THanks!
I would do the filtering in the viewmodel. So I would create a filtered collection something like availableSkills
self.availableSkills = ko.computed(function() {
return ko.utils.arrayFilter(self.skills(), function(item) {
return !item.isDeleted();
})
});
And then I would use this in the selects:
<select data-bind="foreach: availableSkills">
<option data-bind="value: name, text: name"></option>
</select>
Demo fiddle.

Categories