Conditional ngRepeat based on dropdown - angularjs

I would like to display a list based on which item is selected in a dropdown.
When I use the code below, I'm getting this error:
TypeError: Cannot read property 'type' of undefined
Any suggestions on how to do this right?
HTML:
<select class="form-control" ng-model="editProject.project.type"
ng-options="project as project.type for project in editProject.options track by project.type">
</select>
<ul class="list-group">
<li class="list-group-item" ng-repeat="benefit in editProject.foods()">{{snack}}</li>
</ul>
Controller:
.controller('EditProjectCtrl', function () {
var editProject = this;
editProject.options = [
{'type': 'Fruits'},
{'type': 'Vegetables'},
{'type': 'Desserts'}
];
editProject.snacks = function() {
if(editProject.project.type == 'Fruits') {return [
'Grapes',
'Oranges',
'Apples',
]}
if(editProject.project.type == 'Vegetables') {return [
'Broccoli',
'Spinache',
'Kale',
]}
else {return [
'Cookies',
'Cake',
'Pie']}
};

You are almost there. There was a mismatch between the ng-model of the select element, and the conditions in the controller. I also replaced benefit in editProject.foods() with snack in editProject.snacks():
<select class="form-control" ng-model="editProject.project" ng-options="project as project.type for project in editProject.options track by project.type"></select>
<ul class="list-group">
<li class="list-group-item" ng-repeat="snack in editProject.snacks()">{{snack}}</li>
</ul>
Because editProject.project is not defined until you select a project, you have to initialize it in the controller:
editProject.project = {};
See fiddle

Related

nya-bs-select with boolean ng-model

How do I get nya-bs-select to use a boolean value on the model?
This is in the view:
<ol id="submitted" class="nya-bs-select" ng-model="submitted" ng-true-value="true" ng-false-value="false">
<li class="nya-bs-option" value="true">
<a>Submitted</a>
</li>
<li class="nya-bs-option" value="false">
<a>Not Submitted</a>
</li>
</ol>
Here is the controller:
$scope.submitted=true;
// $scope.submitted="true";
Here is the full plunkr:
https://plnkr.co/edit/iMvRDEr6s9zT6C34gM1y?p=preview
The only way to achieve this is by using an object as option and not a value like in this demo plnkr:
View
<ol class="nya-bs-select" ng-model="myModel">
<li nya-bs-option="option in options">
<a>{{option.name}}</a>
</li>
</ol>
Application
var app = angular.module('plunkerApp', ['nya.bootstrap.select']);
app.controller('MainCtrl', function($scope) {
$scope.options = [
{
value: true,
name: 'TRUE SELECTED'
}, {
value: false,
name: 'FALSE SELECTED'
},
];
});

knockout js - Display selected nested checkboxes

I have some code that lists some categories and subcategories with checkboxes but i can not get it to show a which checkboxes have been checked in a nested ul. It does return the selected items but not in a ul list.
please could you show me how to display the selected categories and sub catagories in a nested ul. Thanks.
var ViewModel = function() {
var self = this;
self.selectedCategories = ko.observableArray();
self.selectedItems = ko.observableArray();
self.categories = ko.observableArray([
{ name: 'Hospitality', items: [ 'Bars', 'Caterers', 'Cafes', 'Food To Go', 'Pubs' ] },
{ name: 'Popup', items: [ 'Food Vans', 'Festivals', 'Markets', 'Beer Garden' ] }
]);
}
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
<ul data-bind="foreach: { data: categories, as: 'category' }">
<li> <input type="checkbox" name="level-1" data-bind="checked: $root.selectedCategories, attr: {value: name}"><span data-bind="text: category.name"></span></input>
<ul data-bind="foreach: { data: items, as: 'item' }">
<li><input type="checkbox" name="level-2" data-bind="checked: $root.selectedItems, attr: {value: item}"><span data-bind="text: item"></span></input></li>
</ul>
</li>
</ul>
<div data-bind="text: selectedCategories"></div>
<div data-bind="text: selectedItems"></div>
I'd suggest to store whether a category is selected, and its selected items, in the categories own model. You can make a computed in your ViewModel to create an array with only selected categories. Here's an example:
var ViewModel = function() {
var self = this;
self.categories = ko.observableArray([{
name: 'Hospitality',
items: ['Bars', 'Caterers', 'Cafes', 'Food To Go', 'Pubs'],
selected: ko.observable(false),
selectedItems: ko.observableArray([])
}, {
name: 'Popup',
items: ['Food Vans', 'Festivals', 'Markets', 'Beer Garden'],
selected: ko.observable(false),
selectedItems: ko.observableArray([])
}]);
self.selectedCategories = ko.computed(function() {
return self.categories().filter(function(cat) {
return cat.selected()
});
});
}
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: { data: categories, as: 'category' }">
<li>
<input type="checkbox" name="level-1"
data-bind="checked: selected, value: name">
<span data-bind="text: name"></span>
<ul data-bind="foreach: { data: items, as: 'item' }">
<li>
<input type="checkbox" name="level-2"
data-bind="checked: category.selectedItems, value: item, enable: category.selected">
<span data-bind="text: item, style: { 'opacity' : (category.selected() ? 1 : 0.5)}"></span>
</li>
</ul>
</li>
</ul>
<h2>Selections</h2>
<ul data-bind="foreach: selectedCategories">
<li>
<div data-bind="text: name"></div>
<ul data-bind="foreach: selectedItems">
<li data-bind="text: $data"></li>
</ul>
</li>
</ul>
Note: You had some invalid HTML in your snippet: you can't put a <span> element in an <input> element.

Dependant ng-repeat in AngularJS

I have a following data structure coming from REST:
scope.taglist =
[ { name: "mylist", tags: ["tag1", "tag2", "tag3", ...]}, { name:
"mylist2", tags: ["tag2.1", "tag2.2", "tag2.3", ...]} ]
In order to present the names of the objects I have the following html:
<div>
<select ng-model="tagNameSelection">
<option ng-repeat="tagObj in taglist" value="{{tagObj}}">{{tagObj.name}}</option>
</select>
</div>
<div class="tagdetails">
<!-- present the list of tags from tagNameSelection -->
</div>
Now I am a little bit of a loss on how to present the tags list of
individual object. I am able to present the array in raw format (by
sticking {{tagNameSelection}} inside the tagdetails div) but when I
try to iterate through those with ng-repeat angular gives a error
message.
Oddly enough when I hard-code one of the tag lists to the scope in controller the ng-repeat works flawlessly.
Maybe you interesting something like this:
HTML
<div ng-controller="fessCntrl">
<div>
<select ng-model="tagNameSelection"
ng-options="tagObj as tagObj.name for tagObj in taglist"
ng-change="change(tagNameSelection)"></select>
</div>
<pre>{{tagNameSelection.tags|json}}</pre>
<div class="tagdetails">
<ul ng-repeat="tag in tagNameSelection.tags">
<li>{{tag}}</li>
</ul>
</div>
</div>
Controller
var fessmodule = angular.module('myModule', []);
fessmodule.controller('fessCntrl', function ($scope) {
$scope.change = function (value) {
};
$scope.taglist = [{
name: "mylist",
tags: ["tag1", "tag2", "tag3"]
}, {
name: "mylist2",
tags: ["tag2.1", "tag2.2", "tag2.3"]
}]
});
fessmodule.$inject = ['$scope'];
See Fiddle

Creating a dynanic form in AngularJS with nested lists

I have a model in AngularJS that is structured like so:
region = { 'substances': [
{ 'id': 123, 'name': 'Hello', 'versions': ['A', 'B', 'C'] },
{ 'id': 456, 'name': 'World', 'versions': ['A', 'B', 'C'] }
]}
I want to be able to display and modify this model in a form. Currently I have nested ng-repeats:
<ul>
<li ng-repeat="substance in region.substances">
<input name="substance[]" class="input-medium" type="text" ng-model="substance.name">
<ul>
<li ng-repeat="version in substance.versions">
<input style="margin-left: 10px;" type="text" name="<% substance.id %>.version[]" class="input-medium" ng-model="version">
</li>
</ul>
</li>
</ul>
(Note: I've redefined AngularJS brackets to be <% %>).
I can modify the name, but I AngularJS prevents me from even typing in the inner inputs. I'm guessing that I'm not binding to the model correctly? Also, how would I go about adding another "substance" that has a name and a list of versions?
Is there a proper way to be naming my inputs?
As suggested by #Yoshi , is always easiest to use object inheritance rather than primitive within nested scopes.
$scope.region = { substances: [
{ name: 'Hello', versions: [{x:'A'},{x: 'B'},{x: 'C'}] },
{ name: 'World', versions: [{x:'A'},{x: 'B'},{x: 'C'}] }
]};
<ul>
<li ng-repeat="substance in region.substances">
<input class="input-medium" type="text" ng-model="substance.name">
<ul>
<li ng-repeat="version in substance.versions">
<input type="text" ng-model="version.x">
</li>
</ul>
</li>
</ul>
Demo

AngularJS - Update selected options for multiple select

I'd like to make a simple "autocomplete". Enter keyword into input and select the result. Then the selected items will be shown. I'm currently stucking in how to change the hidden select and show selected items. Could you help me?
<div ng-controller="MyCtrl">
<input type="search" ng-model="query">
<ul ng-repeat="game in games | filter:query" ng-show="query.length >= 2 && (games | filter:query).length">
<li><a ng-click="selectGame(game.id)">{{ game.name }}</a></li>
</ul>
<select multiple name="games" style="display:none;" ng-options="game.id as game.name for game in games"></select>
<ul class="selected-games">
<li>{{ game.name }} - {{ game.year }}</li>
</ul>
</div>
<script type="text/javascript">
function MyCtrl($scope, $http) {
$http.get('/ajax/all/games/').success(function(data){
$scope.games = data;
});
$scope.selectGame = function() {}; //?
}
//MyCtrl.$inject = ['$scope', '$http'];
// JSON data from URL
var games = [
{'id': 1, 'name': 'Halo', 'year': '2005'},
{'id': 2, 'name': 'Final Fantasy', 'year': '2008'},
{'id': 3, 'name': 'Guitar Heroes', 'year': '2008'},
{'id': 4, 'name': 'Warcraft', 'year': '2003'},
{'id': 5, 'name': 'Starcraft II', 'year': '2010'},
{'id': 6, 'name': 'Fifa 12', 'year': '2012'},
];
</script>
Its hard to understand what your desired result is, but check out my updates here: http://jsfiddle.net/rS6Hz/1/. I added a new variable to the scope, an array called selectedGames and implemented the ng-click by adding to that array.
$scope.selectedGames = [];
$scope.selectGame = function(game) {
$scope.selectedGames.push(game);
};
Then, in the display, you have to add an ng-model to the select for it to do anything (as far as I can tell) and the ul of selected-games needs an ng-repeater to loop over the selectedGames
<select multiple name="games" ng-model="something" ng-options="game.id as game.name for game in selectedGames"></select>
<h1>Selected Games</h1>
<ul class="selected-games">
<li ng-repeat="game in selectedGames">{{ game.name }} - {{ game.year }}</li>
</ul>
(I removed the display: none; on the select in order to see it.
Here is another way, without using a separate variable:
http://jsfiddle.net/9Ag9r/
Basically:
<ul class="selected-games">
<li ng-repeat='game in games | filter:{selected:true}'>{{ game.name }} - {{ game.year }}</li>
</ul>
I believe it is a cleaner solution than the accepted one

Resources