I have three variables in my maincontroller, one for select person, one for genre associated with selected person name, and an array of objects with data. I bind the data together in select element enviroment, but now my goal is to output selected items in paragraph for further manipulation, i managed to output selected person but it appears in vertical aligment. Can someone show me how to output for example in my case let's say this, I select Chris and in my paragraph I want to get "Genre that Chris listen are Indie, Drumstep, Dubstep and Electro"
myApp.controller('mainController', function($scope){
$scope.selectedPerson = 0;
$scope.selectedGenre = null;
$scope.people = [
{ id: 0, name: 'Leon', music: [ 'Rock', 'Metal', 'Dubstep', 'Electro' ] },
{ id: 1, name: 'Chris', music: [ 'Indie', 'Drumstep', 'Dubstep', 'Electro' ] },
{ id: 2, name: 'Harry', music: [ 'Rock', 'Metal', 'Thrash Metal', 'Heavy Metal' ] },
{ id: 3, name: 'Allyce', music: [ 'Pop', 'RnB', 'Hip Hop' ] }
];
});
HTML Template
<!DOCTYPE html>
<head>
<title>Learning AngularJS</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js" type="text/javascript"></script>
<script type="text/javascript" src='app.js'></script>
<script type="text/javascript" src='maincontroller.js'></script>
</head>
<body>
<div id='content' ng-app='myAng' ng-controller='mainController'>
<select ng-model='selectedPerson' ng-options='list.name for list in people'></select>
<select ng-model='selectedGenre'>
<option ng-repeat='genre in people[selectedPerson.id].music'>{{genre}}</option>
</select>
<p ng-model='people' ng-repeat='person in people[selectedPerson.id].name'>{{person}}</p>
</div>
</body>
</html>
i managed to output selected person but it appears in vertical aligment.
You run ng-repeat directive on single String. this is a reason why you get something like:
C
h
r
i
s
Maybe something like:
<p>Genre that {{people[selectedPerson.id].name}} listen are {{people[selectedPerson.id].music.join(', ')}}<p>
Demo
<select ng-model='selectedPerson' ng-options='list as list.name for list in people'>
<option value="">-- Select Person --</option>
</select>
<select ng-model='selectedGenre'>
<option ng-repeat='genre in people[selectedPerson.id].music'>{{genre}}</option>
</select>
<p>Genre that {{people[selectedPerson.id].name}} listen are {{people[selectedPerson.id].music.join(', ')}}<p>
Related
I have a group of selects but want them all to work differently with v-model without creating separate data properties for them all.
In the example, select 1 and select 2 are one group and select 3 and select 4 are another.
When one select select 1, the expected behavior should be that, it does not affect select 2, etc.
My guess is may be a computed property for this? but can't get my head around the proper implementation
Js fiddle: https://jsfiddle.net/uxn501h2/8/
Code snippet:
new Vue({
el: '#app',
template: `
<div>
Select 1: <select v-model="selectedPerson">
<option v-for="person in people" :value="person.key">{{person.name}}</option>
</select>
Select 2: <select v-model="selectedPerson">
<option v-for="person in people" :value="person.key">{{person.name}}</option>
</select>
<h4>Selected 1 person key : {{selectedPerson}}</h4>
<h4>Selected 2 person key: {{selectedPerson}}</h4>
<br/>
Select 3: <select v-model="selectedPersonTwo">
<option v-for="person in people" :value="person.key">{{person.name}}</option>
</select>
Select 4: <select v-model="selectedPersonTwo">
<option v-for="person in people" :value="person.key">{{person.name}}</option>
</select>
<h4>Selected 3 person Two key: {{selectedPersonTwo}}</h4>
<h4>Selected 4 person Two key: {{selectedPersonTwo}}</h4>
</div>
`,
data: {
people: [{
key: 1,
name: "Carl"
},
{
key: 2,
name: "Carol"
},
{
key: 3,
name: "Clara"
},
{
key: 4,
name: "John"
},
{
key: 5,
name: "Jacob"
},
{
key: 6,
name: "Mark"
},
{
key: 7,
name: "Steve"
}
],
selectedPerson: "",
selectedPersonTwo: ""
}
});
.required-field > label::after {
content: '*';
color: red;
margin-left: 0.25rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<body>
<div id="app"></div>
</body>
It looks to me that you'd like to use two-way binding, but with more control between them in the middle. My suggestion would be:
Do not use <select v-model="selectedPerson">
Instead split them to <select :value="selectedPersonValue" #input="selectedPersonOutput> (which is basically the same thing, but you can specify different input and outputs), where selectedPersonValue can be a computed property or a regular property in data(), and selectedPersonOutput should be a method that will be called when select value changes.
This way you can directly decide what happens on each step.
PS: If you want to influence your property selectedPersonValue from a method, you might consider changing it to data() property and add a watch to it. See what works best for you.
Once I use ng-options for a select I am unable to get dafault selection to work on nested json objects.
once I have a bit more complicated json and the select should handle a child object my select does not default select the proper value.
Given test = {"id":3,"title":"Test","product":{"id":4,"name":"Test1"}} as my ng-model test.product and
[{
"id": 4,
"name": "Test1"
}, {
"id": 5,
"name": "Test2"
}]
as my selection option. (see http://embed.plnkr.co/mpnislw77UBSEdHl4UKN/)
I seem to be unable to figure out how to facilitate default selection.
If you use track by item.id it works - http://embed.plnkr.co/mpnislw77UBSEdHl4UKN. The marked answer was not very obious since the ng-model is nested in iself. but it contains the correct information.
The only problem with your code is that you've assigned a new object to $scope.test.product and you're using it as the ng-model of the dropdown.
This makes AngularJS unable to find it inside the possible values, which are $scope.testarray. AngularJS will compare two objects by their reference, which you broke when you assigned a new object to $scope.test.product.
To make it working, change $scope.test as follows:
$scope.test = {
"id": 3,
"title": "Test",
"product": $scope.testarray[1]
}
This is how to select with ngOptions and setting a default value
Example
angular.module('defaultValueSelect', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.data = {
availableOptions: [
{id: '1', name: 'Option A'},
{id: '2', name: 'Option B'},
{id: '3', name: 'Option C'}
],
selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
};
}]);
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>
<body ng-app="defaultValueSelect">
<div ng-controller="ExampleController">
<form name="myForm">
<label for="mySelect">Make a choice:</label>
<select name="mySelect" id="mySelect"
ng-options="option.name for option in data.availableOptions track by option.id"
ng-model="data.selectedOption"></select>
</form>
<hr>
<tt>option = {{data.selectedOption}}</tt><br/>
</div>
</body>
</html>
try this, hope it will help
<option value="" ng-if="false"></option>
I have this models:
var data = [
{
id: 1,
level:1,
name:"X1",
subChildren:[{
id:3,
level:2,
name:"X1-1",
subChildren:[...]
}]
},
{
id: 2,
level:1,
name:"X2",
subChildren:[{
id:4,
level:2,
name:"X2-2",
subChildren:[...]
}]
}....];
var levels=[{ level:1,.. },{ level:2,.. },...];
What I want is to show the data in html <select> element, and cascade them depending on the selected parent. i.e:
level 1:
<select>
<option>X1</option>
<option>X2</option>
</select>
-
level 2: (subChildren)
<select>
<option>X1-1</option>
</select>
-
level 3 (sub subChildren)
<select>
<option>X1-1-1</option>
</select>
This is only a non-functional demonstration for what I want to show, when you choose one of the parents it will cascade the next <select> which should be the next level (and contains the sub children) and so on..
The problem is I don't know the number of levels or the number of parents or subChildren, it's all dynamic, and don't know how to do this without writing a lot of native code.
The whole idea is I want to iterate over levels array and create the <select> tags.
This solution works only if you know the maximum number of subchildren you will encounter.Please check the plunkr Plnkr
// Code goes here
var app = angular.module('Dropdown', []).controller('DpdController', function($scope) {
$scope.data = [{
id: 1,
level: 1,
name: "X1",
subChildren: [{
id: 3,
level: 2,
name: "X1-1",
subChildren: [{
id: 4,
level: 3,
name: "X1-2"
}]
}]
}];
$scope.logValue = function(value) {
console.log(value);
}
});
<!DOCTYPE html>
<html ng-app="Dropdown">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.2/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="DpdController">
<select name="repeatSelect" id="repeatSelect" ng-model="selectedValue" ng-change="logValue(selectedValue)" ng-options="option.name for option in data">
</select>
<span ng-if='selectedValue'>
<select name="repeatSelect1" id="repeatSelect1" ng-model="selectedValue1"
ng-change="logValue(selectedValue1)"
ng-options="option.name for option in selectedValue.subChildren">
</select>
</span>
</body>
</html>
I have hierarchical data set. There is one fixed root unit.
What I want to do is to make this tree browsable with dependent selects.
I have created a simple plunkr example with a fixed dataset.
http://plnkr.co/edit/Bz5A1cbDLmcjoHbs5PID?p=preview
The data format in the example mimics the format I would get from a server request in "real" life.
This working fine in this simple first step. What is missing is, that when a user changes a selection somewhere in the middle, the select boxes and the ng-model binding below the new selection need to be destroyed.
So when I select Europe->France->Quimper and change "Europe" to "Asia" - then there should be "Asia" as the first select box and a second one the Asia countries.
Is there an "Angular" way to deal to deal with this? Any other hint is appreciated also ;)
<!DOCTYPE html>
<html ng-app="app">
<head>
<link data-require="bootstrap#3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<script src="https://code.angularjs.org/1.3.17/angular.js" data-semver="1.3.17" data-require="angular.js#1.3.17"></script>
</head>
<body>
<div ng-controller="Ctrl">
<select ng-repeat="select in selects track by $index" ng-model="$parent.boxes[$index]">
<option ng-repeat="child in select.children" ng-click="expandSelects(child)">{{child.name}}</option>
</select>
<ul>
<li ng-repeat="item in boxes">{{ item }}</li>
</ul>
</div>
<script>
var app = angular.module('app', []);
app.controller('Ctrl', ['$scope', function($scope) {
var data = {
'europe': {
name: 'europe',
children: [{
name: 'france',
parent: 'europe'
}, {
name: 'italy',
parent: 'europe'
}],
},
'asia': {
name: 'asia',
children: [{
name: 'japan',
parent: 'asia'
}, {
name: 'china',
parent: 'asia'
}],
},
'france': {
name: 'france',
children: [{
name: 'paris',
parent: 'france'
}, {
name: 'quimper',
parent: 'france'
}]
}
};
var root = {
name: 'world',
children: [{
name: 'europe',
parent: 'world'
}, {
name: 'asia',
parent: 'world'
}, ]
};
$scope.selects = [root];
$scope.expandSelects = function(item) {
var select = data[item.name];
if (select) {
$scope.selects.push(select);
}
}
$scope.$watch('boxes', function(item, old) {
}, true);
}]);
</script>
</body>
</html>
This is a classic example of cascading dropdowns, with the added challenge of an unknown number of levels in the cascade. I combined the data set into one object for simplicity, added labels for the dropdowns, and simplified the select element.
This solution allows for any number of levels, so if you needed data below the city level, you could add it without changing any code, as illustrated by the "Street" example I added to Paris.
select {
display: block;
}
<!DOCTYPE html>
<html ng-app="app">
<head>
<link data-require="bootstrap#3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<script src="https://code.angularjs.org/1.3.17/angular.js" data-semver="1.3.17" data-require="angular.js#1.3.17"></script>
</head>
<body>
<div ng-controller="Ctrl">
<div ng-repeat="select in selects track by $index" ng-if="select.children">
<label>{{ select.optionType }}</label>
<select ng-model="selects[$index + 1]" ng-options="child.name for child in select.children" ng-change="clearChildren($index)"></select>
<hr />
</div>
</div>
<script>
var app = angular.module('app', []);
app.controller('Ctrl', ['$scope', function($scope) {
var data = {
optionType: 'Continent',
name: 'World',
children: [
{
optionType: 'Country',
name: 'Europe',
children: [
{
optionType: 'City',
name: 'France',
children: [
{
optionType: 'Street',
name: 'Paris',
children: [
{
name: 'First'
},
{
name: 'Second'
}
]
},
{
name: 'Quimper'
}
]
},
{
name: 'Italy'
}
]
},
{
optionType: 'Country',
name: 'Asia',
children: [
{
name: 'Japan'
},
{
name: 'China'
}
]
}
]
};
$scope.selects = [data]
$scope.clearChildren = function (index) {
$scope.selects.length = index + 2;
};
}]);
</script>
</body>
</html>
To go to the children in your hierachy is not as hard as it may seem. If you set up your select with angular and let it do most of the selection for you (for example using ng-options instead of ng-repeating the tag itself), and tell it what options there are, then the list of children you are trying to render just becomes a standard ng-repeat of the children that were picked from the select above.
I modified your plunker to show you how you could accomplish that a slightly different way.
http://plnkr.co/edit/zByFaVKWqAqlR9ulxEBt?p=preview
Main points I changed were
$scope.expandSelects = function() {
var select = data[$scope.selected.name];
if (select) {
console.log('changed');
console.log(select);
$scope.chosen = select;
}
}
Here i just grab the chosen item which the will use. Then the ends up looking like.
<ul>
<li ng-repeat="item in chosen.children">{{ item.name }}</li>
</ul>
The only other set up that was really needed was setting up the with ng-options and giving it a model to bind to.
<select ng-options="child.name for child in selects.children"
ng-model="selected" ng-change="expandSelects()">
</select>
Use can use a filter on the second select to filter de options based on the previous selection.
For example, you can have a first selection to choose the continent:
<select ng-options="c for c in continents" ng-model="selectedContinent" ></select>
and a second selection for the coutries:
<select ng-options="c.name for c in countries | filter : {parent:selectedContinent}" ng-model="selectedCountry" ></select>
Made a fiddle with a simplified data structured just to show how the filter works: http://jsfiddle.net/marcosspn/oarL4n78/
I want to disable a particular option from AngularJS dropdown.
It should be listed in the dropdown but should not allow it to be selected. So i need to disable it.
MyFile.tpl.html
<select class="form-control" ng-model="selectedFruits"
ng-options="fruit as fruit.name for fruit in fruits">
</select>
MyController.js
$scope.fruits = [{'name': 'apple', 'price': 100},{'name': 'guava', 'price': 30},
{'name': 'orange', 'price': 60},{'name': 'mango', 'price': 50},
{'name': 'banana', 'price': 45},{'name': 'cherry', 'price': 120}];
Here all the fruit names should be listed in the dropdown but mango and cherry should be disabled and should not allow the user to select it.
Is it possible? If possible, please let me know the solution please.
select options are disabled with disabled attribute. Since ng-options doesn't support disabling, you'll have to generate options within ng-repeat and set ng-disabled based on requirements.
Template:
<select class="form-control" ng-model="selectedFruits">
<option
ng-repeat="fruit in fruits"
ng-disabled="disabledFruits.indexOf(fruit.name) !== -1"
ng-value="fruit">
{{fruit.name}}
</option>
</select>
Inside controller:
$scope.disabledFruits = ["mango", "cherry"]
JSBin.
Just came across this and it worth mentioning that this is possible as of Angular version 1.4.0-rc.1
here are docs ngOptions
and some conversations Angular Github
HTML:
<!DOCTYPE html>
<html ng-app="testApp">
<head>
<script src="https://code.angularjs.org/1.4.0-rc.1/angular.js"></script>
<link href="style.css" rel="stylesheet" />
<script src="script.js"></script>
</head>
<body ng-controller="testController">
<select ng-model="myPerson" ng-options="person.name disable when person.isDisabled for person in people">
</select>
</body>
</html>
JS:
var app = angular.module("testApp", []);
app.controller("testController", function($scope) {
$scope.people = [{
"id": "0",
"name": "Homer",
"surname": "Simpson",
"isDisabled": false
}, {
"id": "1",
"name": "Peter",
"surname": "Griffin",
"isDisabled": false
}, {
"id": "2",
"name": "Philip",
"surname": "Fry",
"isDisabled": false
}, {
"id": "3",
"name": "Humpty",
"surname": "Dumpty",
"isDisabled": true
}, ];
$scope.myPerson = $scope.people[2];
});
and Plunker
If you set disabled value as default it wont work and you will see blank selected item instead.