Ng-option directive cant get access to nested array value - arrays

Help
I'm trying to output different class options(economy/business) with ng-options.
Here is the syntax and json information .
Cant get it working
<select ng-model="mySelect" ng-options="item for item in items ">
</select>
$scope.items = [
{
"id": 2,
"codeName": "class",
"friendlyName": "Class",
"options":
[
{
"id": 15,
"displayOrderNo": 0,
"optionName": "Economy"
},
{
"id": 16,
"displayOrderNo": 1,
"optionName": "Business"
},
{
"id": 36,
"displayOrderNo": 2,
"optionName": "First Class "
}
]
}
];

Related

Angularjs - Set default option in select with dynamic ng-model

I have this problem: i created a selects inside a ng-repeat, the ng-model of each select is dinamically generated.
I need to set a default value to these selects, but i don't know how i can do this
HTML
<div ng-controller="ricercaAttivita">
<div class="accordion-group" ng-repeat="masterAttribute in masterAttributes">
<select class="trip dark" ng-change = "search(1, true, true)" ng-model="masterAttribute.Id" ng-options="attr.Id as attr.Value for attr in masterAttribute.Values">
<option value="">Tutte</option>
</select>
</div>
</div>
APP.JS
var tantoSvagoApp = angular.module('tantoSvagoApp');
tantoSvagoApp.controller("ricercaAttivita", function ($scope) {
$scope.masterAttributes = {"id" : "11", nome" : "MARCHE", "values" :
[{ "id": "114", "nome": "ANCONA" }, { "id": "116", "nome": "ASCOLI PICENO" }]
},
{"id" : "12", nome" : "LOMBARDIA", "values" :
[{ "id": "120", "nome": "MILANO" }, { "id": "121", "nome": "BERGAMO" }]
};
});
The ng-model of my select is "masterAttribute.Id", i need to loop every generated select and, in certain conditions, set a particular default option selected.
Something like
$scope.masterAttribute.Id = value;
How i can do this?
Anyone can hel me PLEASE?
just set the selected value object to $scope.masterAttribute. In your controller add
$scope.masterAttribute = masterAttribute.Values[0];
hope this will help.
$scope.masterAttributes should be an array [],
$scope.masterAttributes=[{
"id": "11",
nome " : "
MARCHE ", "
values " : [{
"id": "114",
"nome": "ANCONA"
}, {
"id": "116",
"nome": "ASCOLI PICENO"
}]
},
{
"id": "12",
nome " : "
LOMBARDIA ", "
values " : [{
"id": "120",
"nome": "MILANO"
}, {
"id": "121",
"nome": "BERGAMO"
}]
And finally set default value in select is,
$scope.masterAttribute = $scope.masterAttributes[0].values[0];

Dynamic form using AngularJS, multiple values binding

I am looking for a best approach to convert a static form to an angular dynamic form. I am not sure how to bind multiple values to the same answer.
The static page is available at: https://jsfiddle.net/hvuq5h46/
<div ng-repeat="i in items">
<select ng-model="i.answer" ng-options="o.id as o.title for o in i.answersAvailable" ng-visible="y.TYPE = 'SINGLE'"></select>
<input type="checkbox" ng-model="i.answer" ng-visible="y.TYPE = 'MULTIPLE'" />
</div>
The JSON file
[
{
"id": 1,
"title": "Are you a student?",
"type": "SINGLE",
"answersAvailable": [
{
"id": 1,
"title": "Yes"
},
{
"id": 2,
"title": "No"
}
],
"answer": [
1
]
},
{
"id": 2,
"title": "Would you like to be an astronaut?",
"type": "SINGLE",
"answersAvailable": [
{
"id": 4,
"title": "Yes"
},
{
"id": 5,
"title": "No"
},
{
"id": 6,
"title": "I am not sure"
}
],
"answer": [
4
]
},
{
"id": 3,
"title": "What is your favourite planet?",
"type": "MULTIPLE",
"answersAvailable": [
{
"id": 7,
"title": "Earth"
},
{
"id": 8,
"title": "Mars"
},
{
"id": 9,
"title": "Jupiter"
}
],
"answer": [
7,
8
]
}
]
Things would be much simpler if you can use a multiple select, but I understand it might be difficult for user to interact (consider something like md-select, which transforms multiple select into a list of checkbox for you)
Multiple select:
<select multiple
ng-model="i.answer"
ng-options="o.id as o.title for o in i.answersAvailable"
ng-if="i.type == 'MULTIPLE'"></select>
Anyway it is completely ok to use HTML checkbox. To do that we would need to bind checkbox model into the data as usual, and then update the answer array simultaneously.
ng-model="o.selected"
ng-change="updateAnswer(i)"
Also, we'll need to copy existing data to model during init.
ng-init="initMultiple(i)"
Working code:
angular.module('test', []).controller('Test', Test);
function Test($scope) {
$scope.items = [{
"id": 1,
"title": "Are you a student?",
"type": "SINGLE",
"answersAvailable": [{
"id": 1,
"title": "Yes"
},
{
"id": 2,
"title": "No"
}
],
"answer": [
1
]
},
{
"id": 2,
"title": "Would you like to be an astronaut?",
"type": "SINGLE",
"answersAvailable": [{
"id": 4,
"title": "Yes"
},
{
"id": 5,
"title": "No"
},
{
"id": 6,
"title": "I am not sure"
}
],
"answer": [
4
]
},
{
"id": 3,
"title": "What is your favourite planet?",
"type": "MULTIPLE",
"answersAvailable": [{
"id": 7,
"title": "Earth"
},
{
"id": 8,
"title": "Mars"
},
{
"id": 9,
"title": "Jupiter"
}
],
"answer": [
7,
8
]
}
]
$scope.initMultiple = function(item) {
item.answersAvailable.forEach(function(option) {
option.selected = item.answer.indexOf(option.id) != -1;
});
}
$scope.updateAnswer = function(item) {
item.answer = item.answersAvailable.filter(function(option) {
return option.selected;
})
.map(function(option) {
return option.id;
});
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app='test' ng-controller='Test'>
<div ng-repeat="i in items">
<select ng-model="i.answer[0]"
ng-options="o.id as o.title for o in i.answersAvailable"
ng-if="i.type == 'SINGLE'"></select>
<label ng-repeat="o in i.answersAvailable"
ng-if="i.type == 'MULTIPLE'"
ng-init="initMultiple(i)">
<input type="checkbox"
ng-model="o.selected"
ng-change="updateAnswer(i)" /> {{o.title}}
</label>
<div>{{i.answer}}</div>
</div>
</div>
Based on my experience, I will make a separation as two Angular models (or usually called services) for the form questions and another one which will collect the answers and eventually will be passed to the backend for further processing. This will provide me a flexibility to maintain both logic and presentation.
var myModule = angular.module('myModule', []);
myModule.factory('QuestionsFormService', function() {
var _question1;
var _question2;
var _question3;
function init(data){
//questions initiation
}
return init;
});
var myModule = angular.module('myModule', []);
myModule.factory('FormDataService', function() {
var _dataAnswer = {}
function init(){
//data initialization
}
function insertData(key, value){
_dataAnswer[key] = value
}
return init;
});
From the example of service models above, you need to make these available to your presentation through the Angular controller with Dependency Injection.
myModule.controller("MyCtrl", function($scope, FormDataService, QuestionsFormService) {
$scope.form_questions = QuestionsFormService.init();
$scope.form_answers = FormDataService.init()
//further logic to make these available on your view on your convenience
});
What you write on the HTML page as an Angular view is already close enough. You only need to change the binding to two models as I propose above. Thank you.

What would be angular ng-option equivalent of this select?

I am struggling to get this into an ng-option. Is it even possible?
<select ng-model="detail_type_id">
<optgroup ng-repeat="type in data.detailTypes" label="{{type.name}}">
<option ng-repeat="t in type.children" value="{{t.id}}">{{t.name}}</option>
</optgroup>
</select>
DetailTypes looks like this:
[
{"id":7,
"parent_id":null,
"name":"Contact",
"children":[
{"id":8,
"parent_id":7,
"name":"Address",
"children":[]
},
{"id":12,
"parent_id":7,
"name":"Something else",
"children":[]
}
]},
{"id":16,
"parent_id":null,
"name":"Other",
"children":[
{"id":10,
"parent_id":16,
"name":"Remarks",
"children":[]}
]
}
]
Child id needs to be selected. Nesting cannot be deeper.
The ngOptions directive does not work with multidimensional objects. So you need to flatten your array to use it.
I wrote a filter for that:
app.filter('flatten' , function(){
return function(array){
return array.reduce(function(flatten, group){
group.children.forEach(function(child){
child.groupName = group.name;
flatten.push(child)
})
return flatten;
},[]);
}
})
And the HTML part would be like this:
<select ng-model="detail_type_id"
ng-options="item.id as item.name
group by item.groupName for item
in data.detailTypes | flatten track by item.id">
</select>
Plunker (version #1 with filter):
https://plnkr.co/edit/dxi7j8oxInv2VRJ1aL7F
I also modified your object to be like this:
[{
"id": 7,
"parent_id": null,
"name": "Contact",
"children": [{
"id": 8,
"parent_id": 7,
"name": "Address",
"children": []
}, {
"id": 12,
"parent_id": 7,
"name": "Something else",
"children": []
}]
}, {
"id": 16,
"parent_id": null,
"name": "Other",
"children": [{
"id": 10,
"parent_id": 16,
"name": "Remarks",
"children": []
}]
}]
EDIT:
After suggestion I wrote another version without the filter, but flattening the array inside the controller.
Additional Controller JS:
$scope.flattenDetailTypes = flattenDetailTypes($scope.data.detailTypes);
function flattenDetailTypes(array){
return array.reduce(function(flatten, group){
group.children.forEach(function(child){
child.groupName = group.name;
flatten.push(child)
})
return flatten;
},[]);
}
Markup:
<select ng-model="detail_type_id"
ng-options="item.id as item.name group by item.groupName for item in flattenDetailTypes track by item.id"></select>
Plunker (version #2 without filter):
https://plnkr.co/edit/D4APZ6

Cascading select options in angular

I cannot get cascading dropdown selects to work pas the first one in angular. On selecting the first option, if it has values for divisions I'd like to show them in the second dropdown, and if the latter has values for workplaces I'd like to show them in the third.
Here is my html
<div ng-controller="SectorController">
<select class="form-control" id="businessUnit" ng-model="divisionsSource"
ng-options="businessUnit.division as businessUnit.sectorName for businessUnit in businessUnits track by businessUnit.id">
<option value=''>Select</option>
</select>
<td>
<select class="form-control" id="division" ng-model="workplacesSource" ng-disabled="!divisionsSource"
ng-options="division.workplace as division.sectorName for division in divisionsSource track by division.id">
<option value=''>Select</option>
</select>
<select class="form-control" id="workplace" ng-disabled="!workplacesSource || !divisionsSource" ng-model="workplace">
<option value=''>Select</option>
<option ng-repeat="workplace in workplacesSource" value='{{workplace}}'>{{workplace}}</option>
</select>
and here is my json feed:
$rootScope.businessUnits = [
{
"id": 1,
"sectorName": "AAA",
"sectorLevel": 20
},
{
"id": 2,
"sectorName": "BBB",
"sectorLevel": 20
},
{
"id": 3,
"sectorName": "CCC",
"sectorLevel": 20
},
{
"id": 4,
"sectorName": "DDD",
"sectorLevel": 20,
"divisions": [
{
"id": 6,
"sectorName": "DDD1",
"sectorLevel": 30
},
{
"id": 7,
"sectorName": "DDD2",
"sectorLevel": 30
},
{
"id": 8,
"sectorName": "DDD3",
"sectorLevel": 30
},
{
"id": 9,
"sectorName": "DDD4",
"sectorLevel": 30,
"workplaces": [
{
"id": 12,
"sectorName": "DDD4 SUB1",
"sectorLevel": 40
},
{
"id": 13,
"sectorName": "DDD4 SUB2",
"sectorLevel": 40
}
]
},
{
"id": 10,
"sectorName": "DDD5",
"sectorLevel": 30
},
{
"id": 11,
"sectorName": "DDD6",
"sectorLevel": 30
}
]
},
{
"id": 5,
"sectorName": "EEE",
"sectorLevel": 20
}
]
Any input will be greatly appreciated.
Your ng-options aren't correct. Here's a plunkr which fixes it: http://plnkr.co/edit/GOIiGXAHnr7nUfv4NHVH?p=preview
Explanations:
businessUnit.division as businessUnit.sectorName
for businessUnit in businessUnits track by businessUnit.id
So, when an option is selected in this first select box, its model (divisionsSource) is set to the selected businessUnit's division. But a businessUnit doesn't have a field named division. It has a field named divisions.
So the code should be
businessUnit as businessUnit.sectorName
for businessUnit in businessUnits track by businessUnit.id
and the next select box should use
division as division.sectorName
for division in divisionsSource.divisions track by division.id

object nested into a nested array, how to implement a custom filter for it?

I have an application that I am constructing with a friend and we have a very big problem: I have a very big json with some nested arrays an objects, I am using a filter with an ng-model="search" the filter (search) works great with the top level array which is named sports, but once I try to search through the leagues array, the filter returns nothing. I saw in another question that I can search(filter) based on nested properties which is exactly what I want. I tried to follow the example answer on that question but I am having a problem trying to solve this. Someone else says: that is not possible with this kind of matching that you are trying because you want to filter through a matching sport.name and all of his matching and not non matching leagues or a non matching sport.name and only his matching leagues.
json
[
{
"name": "Cricket",
"leagues": []
},
{
"name": "NBA Games",
"leagues": [
{
"name": "NBA",
"sport": {
"id": 8,
"name": "NBA Earliest"
},
"lineType": "G",
"priority": [
1,
3
],
"part": "0"
}
]
},
{
"name": "COLLEGE Basketball",
"leagues": [
{
"name": "College - NCAA BASKETBALL",
"sport": {
"id": 24,
"name": "College Basketball"
},
"lineType": "G",
"priority": [
0,
4
],
"part": "0"
},
{
"name": "NCAA BASKETBALL ADDED GAMES",
"sport": {
"id": 24,
"name": "College Basketball"
},
"lineType": "G",
"priority": [
1,
4
],
"part": "0"
},
...
my html
<input type="search" ng-model="search">
<div ng-repeat="sport in sports | filter: query">
<!-- searching (filtering) great -->
<div>{{sport.name}}</div>
</div>
<div ng-repeat="league in sport.leagues | filter: query">
<!-- here is not filtering at all -->
{{league.name}}
</div>
</div>
can I do it this way I am trying or how do I implement a custom filter for this ?

Resources