Vue JS for updating checkboxes based on radio selection - checkbox

I basically have the same question as this guy, but using Vue JS instead of jQuery.
I have a list of N groups bound to my array ensemble_groups and represented by radio buttons. Selected value is mapped to selected_group.
I have a list of actors bound to my array cast with the variables actor_id, actor_name and groups. Each actor is pre-assigned to any number of groups. They're represented by checkboxes and mapped to an array visible_actors (when checked).
Here's my Vue JS powering the above data (I imagine the method is all jacked up, and I probably need a computed property of some sort):
new Vue({
el: '#schedule-builder',
data: {
selected_group: 'Entire Cast',
visible_actors: [],
ensemble_groups: [
"Entire Cast",
"Leads",
"Dancers",
"Children",
"Deselect All",
],
cast: [
{
actor_id: "123",
actor_name: "Carl",
groups: ["Entire Cast","Leads",],
},
{
actor_id: "234",
actor_name: "Max",
groups: ["Entire Cast","Leads","Children",],
},
{
actor_id: "345",
actor_name: "Sheryl",
groups: ["Entire Cast","Dancers",],
},
{
actor_id: "456",
actor_name: "Chip",
groups: ["Entire Cast","Children",],
},
],
},
methods: {
selectGroup: function() {
// uncheck all
visible_actors=[];
// add people in this group to visible_actors
for person in cast {
if (person.groups.indexOf(selected_group) > -1) {
visible_actors.push(person.actor_id);
}
}
}
})
When a user clicks on a radio button for a group, I want to select only the actors' checkboxes who are in that group. So if the user selects "Children", only the actors in the "Children" group should be checked (Max and Chip, per my example).
And, obviously, checking an actor (rather than a group) shouldn't affect the rest of the selections. I mention this because I got it partially working at one point, where selecting a group also selected the correct people, but when I clicked on a person suddenly everyone else was deselected. User can click either a group OR a person, and the expected behavior is that
Here's my HTML template:
<div id="schedule-builder">
<div class="select-groups">
<h3>Ensemble Groups</h3>
<template v-for="group in ensemble_groups">
<input name="select_group[]" id="group_#{{ $index }}"
v-model="selected_group"
:value="group"
#click="selectGroup"
type="radio">
<label for="group_#{{ $index }}">#{{ group }}</label>
</template>
</div>
<div class="select-individuals">
<h3>Cast Members</h3>
<template v-for="person in cast">
<input name="actors[]" id="actor-#{{ $index }}"
v-model="visible_actors"
:value="person.actor_id"
:checked="visible_actors.indexOf(person.actor_id) > -1"
type="checkbox">
<label for="actor-#{{ $index }}">
#{{ person.actor_name }}
</label>
</template>
</div>
</div>
Any help is appreciated... I've been banging my head on it for a couple days already.

This is a tough question to answer well but I'll try.
I would not rely on a computed property for the checked state. Let v-model handle that for you. You can do
<input
type="checkbox"
name="actors[]"
v-model="selected_actors"
:value="actor">
and that will manage the array of selected_actors for you as their values change.
I'm at work and plan on elaborating on this answer a little later but here's a fiddle of how I'd approach the situation: https://jsfiddle.net/crswll/806shzzg/7/

Related

How to run multiple successive select buttons in AngularJS

I facing an issue with having multiple selects in angularJS where each one of them is linked to the previous one and the value depended on the previous item selected which looks like could be done easily by angular but I am having a hard time figuring out how do I make the index of one select be passed to another select and at the same time making it unresponsive until some value is selected.
I also created a fiddle for the same for people to fiddle around with it.
Here is the concerned HTML
<div ng-app="myApp">
<div ng-controller="testController">
<select ng-model="carBrand" name="carBrand" required ng-options=" brand for brand in brands"></select>
<select ng-model="carModel" name="carModel" required ng-options="model.name for model in cars[0]"></select>
<!--I want the car brand(cars[0]) to be dynamic here. It should be prefreberably blacked out or uneditable until a Car brand is selected and once that particular brand is selected all the models pertaining to that brand only should be displayed in the ajoining select button-->
</div>
</div>
and an example app.js. Find the complete one at the fiddle
var app = angular.module('myApp', []);
app.controller("testController", function($scope) {
$scope.brands = ['Ford', 'Honda', 'Hyundai', 'Mahindra',
'Maruti Suzuki', 'Nissan', 'Renault', 'Skoda', 'Tata', 'Toyota', 'Volksvagen'
];
$scope.carBrand = $scope.brands[0];
$scope.cars = [];
/*These cars[0] and cars[1] are static declared but could well be called from a REST API endpoint in angular. For simplicity lets say they are already present. */
$scope.cars[0] = $scope.cars[0] = [{
name: "Figo",
capacity: 45
}, {
name: "Ecosport",
capacity: 52
}, {
name: "Fiesta",
capacity: 45
}, {
name: "Endeavour",
capacity: 71
}];
});
How do I solve the issue of getting an index from one select and passing it to the other to make this work and probably an additional perk would be to make it unresponsive in case no brand is selected.
Try ng-change:
<select ng-model="carBrand" name="carBrand" required ng-options=" brand for brand in brands"
ng-change="selectedCar(carBrand)"></select>
This returns the index of the selected brand:
$scope.selectedCar = function(brand) {
$scope.carIndex = $scope.brands.indexOf(brand);
};
Use it with the other dropdown as:
<select ng-model="carModel" name="carModel" required
ng-options="model.name for model in cars[carIndex]"></select>
Working Fiddle
When you select something from the first select, carBrand goes from undefined to the selected brand. You thus want the second select to be disabled if the carBrand is undefined (falsy):
<select ng-disabled="!carBrand" ...>
Then, you need to second select to contain the models associated to the selected brand (which is carBrand). So you need something like
<select ng-options="model.name for model in getModelsOfBrand(carBrand)" ...>
Now just implement this getModelsOfBrand(carBrand) function in the scope. It would be much easier if you had a better object model, like for example:
$scope.brands = [
{
name: 'Ford',
models: [
{
name: 'Figo',
capacity: 45
},
...
]
},
...
];
Then it would be as easy as
<select ng-options="model.name for model in carBrand.models" ...>

Angularjs: connecting a set of buttons' output to a custom filter

I'm trying to write an app that lets you select a bunch of buttons each connected to a different array of restrictions for a search through another array. I already have the buttons connected to the array of possible restrictions and I'm using ng-repeat to create a button for each restriction from that array.
What I can't get is a way to get each button to add its restriction to an array for a filter to search through my database.
I have forked your code, see here: http://plnkr.co/edit/uyr8eSHMe3sFf6Pzwf58?p=preview
I believe you didn't ask how to filter your recipes, but how to get the filter string to the controller?
Controller
$scope.addDietaryRestriction = function (kind, restr) {
console.log ($scope.filter);
$scope.filter[kind] = restr;
console.log ($scope.filter);
}
$scope.submit = function () {
console.log ($scope.filter);
console.log ($scope.filterConfig);
}
HTML
<div>
<h2>What courses?</h2>
<button ng-repeat="course in filterConfig.courses" class="buttons" ng-click="addDietaryRestriction('course', course)">
{{course}}</button>
<br><br>
</div>
Mind the two args in the addDietaryRestriction() call in ng-click().
Personally, I'd also create the button-groups with an ng-repeat:
$scope.filterConfig = {
dietaryRestrictions: {
headline: "Dietary Restrictions:",
values: [
'Vegetarian',
'Meat',
'Nuts',
'Wheat',
'Dairy',
'Kosher',
'Halal'
]
},
courses: {
headline: "What courses?:,
values: [
'starter',
'main',
'dessert'
]
}, ....
and in the HTML:
<div ng-repeat="(key, value) in filterConfig track by $index">
<h2>{{value.headline}}</h2>
<button ng-repeat="course in value.values" class="buttons" ng-click="addDietaryRestriction(key, course)">
{{course}}</button>
<br><br>
</div>

List items by type in AngularJs using ng-repeat

I have some items, lets say they are Cars. I am using ng repeat to list them.
Cars also have tires. Let's say I want to list all of the tire options, but there are a several different types of tires, so we want to separate them by their type {summer, road, racing, etc....):
<div class="col-md-4" ng-repeat="individualCar in allCars" ng-show="CarTypeFilter[individualCar.type]">
<div class="">
{{individualCar.name}}
</div>
<ul>
<!-- This is the list of all one type of tires -->
<li class="TireType1" ng-repeat="tire in individualCar.tires" ng-show="CarTireFilter[tire.type]">
{{tire.name}}
</li>
<!-- This is another list of all another type of tires -->
<li class="TireType2" ng-repeat="tire in individualCar.tires" ng-show="CarTireFilter[tire.type]">
{{tire.name}}
</li>
</ul>
</div>
This isn't quite working, since there isn't a separate list of tire types per Car on the Controller $scope, and Im not sure if I need to build one to reference. How do I filter or list the types of tires separately using ng-repeat?
I plan on styling them differently, hence the distinction needed.
Example JSON:
{
"jokes":[
{
"id:":1,
"name":"Tesla",
"type":"CAR",
"Tires":[
{
"id":1,
"type": "summer",
"name":"Goodyear"
},
{
"id":2,
"type": "summer",
"name":"Kuhmo"
},
{
"id":3,
"type": "winter",
"name":"Perelli"
},
{
"id":4,
"type": "racing",
"name":"Cooper"
}
]
},
{...}
]
}
In the controller, I have an associative array that stores the different types {summer, racing, etc) as the key, and a boolean value, so that when they want to see each option via a checkbox, the items show in the ng-repeat:
$scope.CarTireFilter = {"summer":true, "racing":false, ... };
If you are wanting to only show items in the list by some specific atrribute then a filter is what you need. See the docs for Filter & OrderBy.
Do not us ng-show rather use this:
div class="col-md-4" ng-repeat="individualCar in allCars|
filter: SET CONDITIONS HERE |
orderBy: SET CONDITIONS HERE">
The other thing I would like suggest is that if you are going to be adding styling based on the various types. You might want to look into doing this in a more angular way using ng-style. Look at the docs ng-style. This approach would allow you add the needed styles based on type and not necessarily need to have separate li tags with different classes. you should try and let angular handle this.

unable to display radio button group in angular js dynamic form

what is the simplest way to display a radio button and dropdown list using templating in angular js? I have a plunker where i'd like to display the radio button group(quest#4) options as dynamic values - i am not sure how to do so. I am having the same issue with the selects(quest#5) as well. Any help is much appreciated.
http://run.plnkr.co/eHxbQn2lm1uTE2JI/
I couldn't see your attempt at using a <select> in your code, so here's an abstracted example, if you had the choices like so:
.controller('AppControl', ($scope)->
$scope.answers =
q1: null
q2: null
$scope.options = {
"option 1": "val1",
"option 2": "val2"
}
)
Then you could make a radio button list would look like this:
<span ng-repeat="(key, value) in options">
<input type="radio" ng-model="answers.q1" ng-value="value"/> {{key}}
</span>
And a select would look like this:
<select ng-model="answers.q2"
ng-options="value as key for (key, value) in options">
</select>
EDIT
To answer the second part of your question below: "how do I use ng-show in this case?":
To do this, you need to add the possibility of having a "show if" type condition in your questions. If there is a condition, then you only want to show the question if that condition is met. Your HTML for each question would change to look like this:
<div ng-repeat="question in questionnaire"
ng-include="'questionnaire'"
ng-show="(question.condition == null) || {{question.condition}}"></div>
Note that you check whether a condition has been specified, and if it hasn't, then the ng-show expression would evaluate to true. If it has, we interpolate that condition so that we can use the same syntax as we would for other ng-shows.
You then just need to adjust your question to include a condition, for example:
{
number: "5",
question: "Which of the following sweets do you like?",
type: "DD",
condition: 'questionnaire[$index-1].answer != "blue"',
values :[
{ name: "hardcandy" },
{ name: "chocolate" },
{ name: "other" },
]
}
questionnaire[$index-1] refers to the previous question ($index is from ng-repeat, check the docs), and .answer only works because I have used ng-model="question.answer" when I answered your previous query. I would personally add this ng-model attribute to all of your questions.
You can see it working here: Plunker

AngularJS filter on empty string

I have a simple Angular filter setup between a select and a list. When a user selects an item from the dropdown, the list is updated to show the matching result. The problem is that I have a "Select..." option first in the dropdown with no value, and when that is the selected value, all items are shown. I suppose that makes sense, but I want the opposite. If the selected option has no value, I don't want to show the list. Here are some relevant bits, followed by a link to a full fiddle:
The dropdown:
<select class="world-list" ng-model="selectedWorld" ng-options="world.worldId as world.worldName for world in allWorlds">
<option value="">Select...</option>
</select>
The list:
<ul class="unstyled" id="charList">
<li ng-repeat="char in characters | filter:selectedWorld">
{{char.charName}} - {{char.charRace}} {{char.charClass}}
</li>
</ul>
And here is a link to the full fiddle, which contains my JSON structures that drives all this: http://embed.plnkr.co/6XUmC5efO0Y1BRNLRUig
What I'm trying to do is rather simple, and I'm pretty new to Angular so I'm sure I'm missing something obvious. Checked the Jabbr room, nobody on. :(
Anyway, thanks for any and all help!
One way to accomplish this is to filter by specific properties of the iteration object:
<ul class="unstyled" id="charList">
<li ng-repeat="char in characters | filter:{worldId: selectedWorld}">
{{char.charName}} - {{char.charRace}} {{char.charClass}}
</li>
</ul>
Plunker
I noticed in your code "script.js" you don't seem to be accounting for the blank option.
I did not test this (I probably should prior to posing this answer), but it should work by placing the "blank" option within your script.js.
app.controller('WorldCtrl', function ($scope, $http) {
$scope.allWorlds = [{
worldId: "",
worldName: ""
},
{
worldId: "b8ee0530-744b-463e-9428-23178f6c7bff",
worldName: "World 1"
},
{
worldId: "81211982-5613-4f9c-b704-7b6fa35faf84",
worldName: "World 2"
},
{
worldId: "df41208e-e8d2-46c9-8299-8f37632a51f8",
worldName: "World 3"
}];
$scope.characters = [{
charClass: "Rogue",
charName: "Vaes",
charRace: "Human",
worldId: "b8ee0530-744b-463e-9428-23178f6c7bff"
},
{
charClass: "Warrior",
charName: "Azash",
charRace: "Orc",
worldId: "b8ee0530-744b-463e-9428-23178f6c7bff"
},
{
charClass: "Mage",
charName: "Anele",
charRace: "Ogre",
worldId: "81211982-5613-4f9c-b704-7b6fa35faf84"
}];
});

Resources