Angular pre-select multiple values in Multi Select field - angularjs

Trying to pre-select multiple values in my selectfield.
My HTML
<select multiple
data-ng-options="e.id for e in myElements"
data-ng-model="mySelect">
</select>
Put data in the select box (works fine)
var elements = [
{ "id": "AAA" },
{ "id": "BBB" },
{ "id": "CCC" },
{ "id": "DDD" },
{ "id": "EEE" },
{ "id": "FFF" },
{ "id": "GGG" }
]
$scope.myElements = elements;
This does NOT work
var preselected = [
{ "id": "BBB" },
{ "id": "DDD" },
{ "id": "FFF" }
]
$scope.mySelect = preselected;
This does NOT work
var preselected = [ "BBB", "DDD", "FFF" ]
$scope.mySelect = preselected;
Anyone got any ideas?

You have two options:
1- Use as and track by if you want objects as selected values (PLUNKER)
ng-options="e as e.id for e in vm.elements track by e.id"
HTML
<select multiple
ng-options="e as e.id for e in vm.elements track by e.id"
ng-model="vm.selecetedValues">
</select>
CONTROLLER
function MainCtrl() {
var vm = this;
vm.elements = [{ "id": "AAA" },{ "id": "BBB" },{ "id": "CCC" }];
vm.selectedValues = [
{ "id": "AAA" },
{ "id": "CCC" }
];
}
2- Only Use as syntax if you want strings or numbers as selected values (PLUNKER)
ng-options="e.id as e.name for e in elements"
first argument e.id is the value of selected option
second argument e.name is the displayed value
In your case: ng-options="e.id as e.id for e in elements"
HTML
<select multiple
ng-options="e.id as e.id for e in vm.elements"
ng-model="vm.selecetedValues">
</select>
CONTROLLER
function MainCtrl() {
var vm = this;
vm.elements = [{ "id": "AAA" },{ "id": "BBB" },{ "id": "CCC" }];
vm.selectedValues= [
"BBB",
"DDD"
];
}

Related

rxjs/Angular2 Loop but show different object of a single associative array

I recently combined two array using rxjs
MyArray = [{
"Field": ["Cars"],
"Type": ["BMW", "Toyota", "Volvo"]
},
{
"Field": ["House"],
"Type": ["Condominium", "TownHouse"],
}
PriceArray = [
{
field: Cars,
distribution: [{"name" : "BMW","price":2},{"name" : "Toyota","price":3}]
},
{
field: People,
distribution: [{"name" : "Condominium","price":3},{"name" : "TownHouse","price":2}]
}]
using rxjs filter
const $MergeData = MyArray.map(val => {
return Object.assign({}, val,this.PriceArray.filter(v => v.Field === val.field)[0])
});
this.mergedArray = $MergeData;
Now it looked this..
mergedArray = [{
"Field": "Cars",
"Type": ["BMW", "Toyota", "Volvo"],
"field" : "Cars",
"distribution" : [
{
"name" : "BMW"
"price": 2 ,
},
{
"name" : "Toyota"
"price": 3 ,
},
{
"name" : "Toyota"
"price": 4 ,
}
]
}, .... (house array here)];
Then I tried to show the item price but its not working
<div *ngFor="let item of mergedArray">
<div *ngFor="let car of item.Field; let i = index">
<p>{{car}} </p>
<p>{{item.distribution.price[i]}} </p>
</div>
</div>
I am hoping for a fix or better if the array should look like this instead
mergedArray = [{
"Field": "Cars",
"Type": ["BMW": 2, "Toyota" : 3, "Volvo" : 4],
}]
Hoping it would me possible as it is much easier to loop.
I think that this is the desired effect, also keep in mind that when using Array.prototype.filter and no elements pass the test the returned value will be [] and if you try to access the [][0] element, the value will be undefined, after that if you try to access some property from that undefined value, it will throw an error.
For example if you try to access the price of Volvo it will throw an error Cannot read property 'price' of undefined, because Volvo doesn't exist in the PriceArray
let priceArray = [
{
"name" : "BMW",
"price": 2
},
{
"name" : "Toyota",
"price": 3
},
{
"name" : "Toyota",
"price": 4
}
];
let myArray = [{
"Field": "Cars",
"Type": ["BMW", "Toyota", "Volvo"]}]
let findPrice= (priceArray,mark)=> priceArray
.find(x=> x.name === mark)
? priceArray.find(x=> x.name === mark).price
: 'No data'
let mergedArray = myArray[0].Type.map(x=> ({[x]:findPrice(priceArray,x)}))
console.log(mergedArray)

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.

Angularjs Splice in Nested Array

Hi can somebody help Removing element from nested json array like this
JSON
[{
"id": 1,
"name": "Furniture & Fixture",
"choice": {
"0": {
"req_goods": "table",
"qty": "10"
},
"1": {
"req_goods": "chair",
"qty": "5"
}
}
}, {
"id": 2,
"name": "Miscellaneous Property",
"choice": {
"0": {
"req_goods": "Office Rent",
"qty": "1"
}
}
}]
here how do I remove choice 1 of id 1 .
HTML
<div ng-repeat="cb in capital_budgets">
<div ng-repeat="choice in choices[$index]">
<input ng-model="cb.choice[$index].req_goods">
<input ng-model="cb.choice[$index].qty">
<button ng-hide="$first" ng-click="removeChoice($parent.$index,$index)">-</button>
</div>
<button ng-click="addNewChoice($index)">+</button>
</div>
JS
$scope.capital_budgets = [{"id":1,"name":"Furniture & Fixture"},
{"id":2,"name":"Miscellaneous Property"}];
$scope.choices = [{}];
$scope.choices[0] = [{}];
$scope.choices[1] = [{}];
$scope.choices[2] = [{}];
$scope.choices[3] = [{}];
$scope.choices[4] = [{}];
$scope.addNewChoice = function(id) {
$scope.choices[id].push({});
};
$scope.removeChoice = function(parent_id, id) {
$scope.choices[parent_id].splice(id, 1);
};
The Above removeChoice() remove last element but I want to remove the element that user choose to remove. please help i have been trying from 2 days.
You can make 'choice' of the array type as follows and use the index of the particular choice in the ng-repeat directive to remove the choice from the choices array.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
vm.removeChoice = removeChoice;
vm.addChoice = addChoice;
function removeChoice(itemId, index) {
for (var i = 0; i < vm.items.length; i++) {
if (vm.items[i].id === itemId) {
vm.items[i].choices.splice(index, 1);
break;
}
}
}
function addChoice(index) {
var id = vm.items[index].choices.length + 1;
vm.items[index].choices.push({
id: id,
req_goods: "",
qty: 0
});
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<div ng-repeat="item in ctrl.items">
<h3>{{item.name}}</h3>
<div ng-repeat="choice in item.choices">
<input type="text" ng-model="choice.req_goods" />
<input type="text" ng-model="choice.qty" />
<button type="button" ng-click="ctrl.removeChoice(item.id, $index)">Remove</button>
</div>
<button type="button" ng-click="ctrl.addChoice($index)">Add</button>
</div>
</div>
</div>
You can remove choice "1" of id 1 using the below code snippet.
var json = [
{
"id": 1,
"name": "Furniture & Fixture",
"choice": {
"0": {
"req_goods": "table",
"qty": "10"
},
"1": {
"req_goods": "chair",
"qty": "5"
}
}
}, {
"id": 2,
"name": "Miscellaneous Property",
"choice": {
"0": {
"req_goods": "Office Rent",
"qty": "1"
}
}
}];
function removeChoice(json, parentId, choice) {
for (var i = 0; i < json.length; i++) {
if (json[i].id === parentId) {
delete json[i].choice[choice];
break;
}
}
}
removeChoice(json, 1, "1");
console.log(json);
If you want the the choice also to be of the same type as its parent element i.e. an array you could change your JSON as follows and do as shown in the below code snippet to remove a choice from the JSON
var json = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
function removeChoice(json, parentId, choiceId) {
for (var i = 0; i < json.length; i++) {
if (json[i].id === parentId) {
for (var j = 0; j < json[i].choices.length; j++) {
if (json[i].choices[j].id === choiceId) {
json[i].choices.splice(j, 1);
break;
}
}
break;
}
}
}
removeChoice(json, 1, 1);
console.log(json);
In both of the above methods I've passed the source you want to modify as a parameter to the removeChoice function whereas you can also directly use a variable available within the scope of execution of the removeChoice function and pass only parentId and choiceId as parameters in the below code snippet, you can replace items with the object on your controller's $scope.If you prefer isolation of the code you can pass the items object as a parameter to the removeChoice function as it won't be dependent on the external components directly being used in the method body, I would suggest to have separation of concerns.
var items = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
function removeChoice(parentId, choiceId) {
for (var i = 0; i < items.length; i++) {
if (items[i].id === parentId) {
for (var j = 0; j < items[i].choices.length; j++) {
if (items[i].choices[j].id === choiceId) {
items[i].choices.splice(j, 1);
break;
}
}
break;
}
}
}
removeChoice(1, 1);
console.log(items);
Try This
$scope.removeChoice = function(parent_id,id) {
var TempArr=[];
var parentLength=$scope.choices[parent_id].length;
for(i=0;i<parentLength;i++ ){
if(parentLength[i]!==id){
TempArr.push(parentLength[i]);
}
if(i==parentLength-1){
$scope.choices[parent_id]=[];
$scope.choices[parent_id]=TempArr;
}
}
};

AngularJS filter on multiple lists of multiple checkboxes

I apologise if this has been answered already, but I'm new to Angular so might have missed it.
I have a need to provide multiple sets of checkbox lists, which need to be combined to create an AND query.
It's on Plunker here http://plnkr.co/OGmGkz22n4J4T8p74yto but enclosed below. At the moment I can select the bottom row and the correct names appear from storeArray, but I cannot work out how to add the Format array into the filter.
I've tried:
<div ng-repeat="store in storeArray | filter:(formatFilter && tillFilter)">
and
<div ng-repeat="store in storeArray | filter:formatFilter:tillFilter">
but they don't work.
Any suggestions please?
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.formatFilter = function(a) {
for (var fmt in $scope.formatsArray) {
var f = $scope.formatsArray[fmt];
if (f.on && a.format.indexOf(f.name) > -1) {
return true;
}
}
};
$scope.tillFilter = function(a) {
for (var till in $scope.tillsArray) {
var t = $scope.tillsArray[till];
if (t.on && a.tills.indexOf(t.name) > -1) {
return true;
}
}
};
$scope.formatsArray = [{
name: "Super",
on: false
}, {
name: "Express",
on: false
}, {
name: "Other",
on: false
}];
$scope.tillsArray = [{
name: "Main",
on: false
}, {
name: "Service",
on: false
}, {
name: "Petrol",
on: false
}];
$scope.storeArray = [{
"id": "1",
"name": "101",
"format": "Super",
"tills": ["Main", "Service", "Petrol"]
}, {
"id": "2",
"name": "102",
"format": "Express",
"tills": ["Main", "Service"]
}, {
"id": "3",
"name": "103",
"format": "Other",
"tills": ["Main", "Petrol"]
}, {
"id": "4",
"name": "104",
"format": "Super",
"tills": ["Service", "Petrol"]
}];
}
While you can chain filters together like this:
<div ng-repeat="store in storeArray | filter:formatFilter | filter:tillFilter)">
This won't fix your problem since the first filter will do it's job, and filter items out that you may want to include in your second filter. I'm not sure of any way to do an "or" filter. Is there any reason you can't do a custom filter that includes both? I modified your plunker with a custom filter:
http://plnkr.co/edit/han1LFl7toTsSX27b9Q0?p=preview
The code isn't super clean... it does the job. :) You may want to polish it up a bit.

Resources