How to conditionally disable an object within an array in Angular - angularjs

I have several select elements on the same page. Each select dropdown contains the same items. I would like to disable an item within the dropdown if it has already been selected in another select element. In other words, I don't want an item to be selected more than once across all of the select elements.
Any thoughts on how to accomplish this?
When I use the following code, nothing is disabled in the dropdown.
Code for controller:
var editProject = this;
editProject.addMore = function() {
editProject.project.fruit.push({});
};
editProject.fruitids = [
{code: 'GOODS', fruit: '1. Apple'},
{code: 'GOODS', fruit: '2. Orange'},
{code: 'GOODS', fruit: '3. Peach'},
];
HTML:
<div ng-repeat="item in editProject.project.fruits">
<select ng-model="editProject.project.fruits[$index]"
ng-options="fruitid.class group by fruitid.code disable when (editProject.project.fruits.indexOf((fruitid)) !== -1)
for fruitid in editProject.fruitids track by fruitid.class">
<option value="">--Select Class--</option>
</select>
</div>
<button ng-click="editProject.addMore()" class="btn btn-default btn-xs" role="button">Add More Classes
</button>

You need to use a function as the expression for the disable parameter in the ng-options directive.
Please see working example1
HTML
<div data-ng-repeat="item in items">
<select data-ng-options="fruitId.fruit disable when isDisabled(fruitId) for fruitId in fruitIds" data-ng-model="items[$index]"></select>
</div>
JS
$scope.isDisabled = function(fruitid) {
return ($scope.items.indexOf((fruitid)) !== -1);
};
This will disable the option in all the select's including the the select where the option was selected. The option will now not be selected any more as it is disabled.
You need to exclude the current fruitId so it is still enabled in the selected select
Please see example2 where the current fruitId is excluded and the selected option is disabled in the other selects
We make sure that the index found is not the index of the current item.
HTML
<div data-ng-repeat="item in items">
<select data-ng-options="fruitId.fruit disable when isDisabled(fruitId, item) for fruitId in fruitIds" data-ng-model="items[$index]"></select>
</div>
JS
$scope.isDisabled = function(fruitid, item) {
return ($scope.items.indexOf((fruitid)) !== -1 && $scope.items.indexOf((fruitid)) != $scope.items.indexOf(item));
};

This code can help to you?
index.html:
<html ng-app>
<head>
<title>Demo</title>
<script type="text/javascript" src="js/lib/angular.min.js"></script>
<script type="text/javascript" src="js/controllers/app.js"></script>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-responsive.min.css">
</head>
<body>
<div class="container" ng-controller="AppCtrl">
<select ng-model="selectedOption" ng-change="change(selectedOption)">
<option ng-repeat="var in myObj.myArr" value={{var.id}}
ng-disabled="var.selectable">
{{var.fruit}}
</option>
</select>
</div>
</div>
</div>
</body>
</html>
app.js:
function AppCtrl ($scope) {
$scope.myObj = {
"myArr":[
{id:0, code: 'GOODS', fruit: '1. Apple', selectable:false},
{id:1, code: 'GOODS', fruit: '2. Orange', selectable:false},
{id:2, code: 'GOODS', fruit: '3. Peach', selectable:false}
]};
$scope.selectedOption = {};
$scope.change = function(id){
var name = $scope.myObj.myArr[id].selectable = true;
};
};

You can:
1- Create an angularjs directive that encapsulate every select/dropdown and assign a unique id to each of them.
2- Bind the array of elements to all directives
3- When the user selects an item you set an item's property (assignedTo) with the unique id of the directive as the value (and clean the property for all other items with this id as value)
4- The select disables elements based on the value of the property (assignedTo !== uniqueId)
View template:
<my-select-directive unique-select-id="1" items="theItems"><my-select-directive>
<my-select-directive unique-select-id="2" items="theItems"><my-select-directive>
<my-select-directive unique-select-id="3" items="theItems"><my-select-directive>
Directive template:
<select ng-model="selectedItem" ng-change="change()">
<option ng-repeat="item in myItems" value={{item.id}}
ng-disabled="item.assignedTo && item.assignedTo !== uniqueSelectId">
{{item.fruit}}
</option>
</select>
Directive code:
//here you can implement logic to remember previous selection, now it doesn't
scope.selectedItem= null;
scope.change = function(){
//needed to sync
//remove the mark of the previous selected item for this dropdown if any
myItems.forEach(function(item) {if (item.assignedTo === scope.uniqueSelectId) item.assignedTo = null;});
//now mark the item as selected in this dropdown
selectedItem.assignedTo = scope.uniqueSelectId;
}
This is not working code, it's only to guide you

Related

How to get selected option in be selected in a dropdown after opening a modal in AngularJS?

I have a select tag like this:
<select... ng-model="someProperty" ng-change="openSomeDialog()">
<option value=""></option>
<option value="Test1">Test1</option>
<option value="Test2">Test2</option>
</select>
The openSomeDialog() function opens a ui.bootstrap.modal directive modal. When the user closes the modal, the dropdown reverts to the initial option which is the empty one (first option) instead of what the user has selected. I also tried to use a watch on the select's ngModel and I get the same issue.
If I put some non modal related logic in the function instead of opening a modal, the selection works fine so it seems the process of opening the modal changes the events workflow or something.
How do I get the dropdown to select what the user has selected before the modal opened, after the modal closes?
I think this might be useful-> https://stackoverflow.com/a/1033982/7192927
Try binding the "selected" attribute to an object/variable as required to your case.
If you are using AngularJS, Instead of using select, you can use md-select of angular material, where u have the trackby attribute to make the option appear
as selected.--> https://material.angularjs.org/latest/api/directive/mdSelect
Ng-Options
Try using ng-options:
// Script
$scope.datarray = ["test1, "test2"];
<!-- HTML -->
<select class="form-control" ng-options="test in dataArray" ng-model="someProperty" ng-change="openSomeDialog()">
<option value=""></option>
</select>
https://embed.plnkr.co/wF3gc5/
EDIT: Updated my answer to better align with your requirements / comment.
Reference
https://docs.angularjs.org/api/ng/directive/select
Snippet
(function() {
"use strict";
var app = angular.module('plunker', ['ui.bootstrap']);
app
.controller("MainCtrl", MainCtrl)
.controller("ModalController", ModalController);
MainCtrl.$inject = ["$scope", "$log", "$uibModal"];
function MainCtrl($scope, $log, $uibModal) {
// Sample Data
$scope.cats = [{
id: 0,
name: "mister whiskers"
}, {
id: 1,
name: "fluffers"
}, {
id: 2,
name: "captain longtail"
}];
$scope.openModal = function() {
// Open the modal with configurations
var modalInstance = $uibModal.open({
templateUrl: 'myModalContent.html', // Points to my script template
controller: 'ModalController', // Points to my controller
controllerAs: 'mc',
windowClass: 'app-modal-window',
resolve: {
cats: function() {
// Pass the Cats array to the Modal
return $scope.cats;
},
selectedCat: function() {
// Pass the selected cat to the Modal
return $scope.selectedCat;
}
}
});
// Handle the value passed back from the Modal
modalInstance.result.then(function(returnedCat) {
if (returnedCat === null || returnedCat === undefined) {
// Do Nothing
return;
}
// We can now update our main model with the modal's output
$scope.selectedCat = returnedCat;
});
}
}
ModalController.$inject = ['$scope', '$timeout', '$uibModalInstance', 'cats', 'selectedCat'];
function ModalController($scope, $timeout, $uibModalInstance, cats, selectedCat) {
// Assign Cats to a Modal Controller variable
console.log("cats: ", cats)
$scope.modalCats = cats;
if (selectedCat !== null || selectedCat !== undefined) {
$scope.selectedModalCat = selectedCat;
}
$scope.submit = function() {
// Pass back modified resort if edit update successful
$uibModalInstance.close($scope.selectedModalCat);
}
$scope.close = function() {
// Pass back modified resort if edit update successful
$uibModalInstance.close(null);
}
}
})();
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css" />
<link data-require="bootstrap-css#3.*" data-semver="3.3.7" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css" />
<!-- JQuery and Bootstrap -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- Angular Stuff -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.9/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.9/angular-touch.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.9/angular-animate.js"></script>
<!-- UI Bootstrap Stuff -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js"></script>
<!-- OUR Stuff -->
<script src="app.js"></script>
<script src="modalController.js"></script>
</head>
<body ng-controller="MainCtrl">
<!-- ==== MAIN APP HTML ==== -->
<div class="container">
<div class="row">
<div class="col-xs-12">
<div class="jumbotron text-center">
<h3>AngularJS - ngOptions and UI Bootstrap Modal</h3>
</div>
</div>
<div class="col-xs-12">
<form class="form">
<div class="form-group">
<label class="form-label">Select Profile:</label>
<select class="form-control" ng-options="cat.name for cat in cats track by cat.id" ng-model="selectedCat" ng-change="openModal()">
<option value="">-- Cat Selection --</option>
</select>
</div>
<div class="well form-group" ng-show="selectedCat !== undefined && selectedCat !== null">
<label>Selected: </label>
<pre>{{ selectedCat }}</pre>
</div>
</form>
</div>
</div>
</div>
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title" id="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body" id="modal-body">
<select class="form-control" ng-options="modalCat.name for modalCat in modalCats track by modalCat.id" ng-model="selectedModalCat">
<option value="">-- Cat Selection --</option>
</select>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="submit()">OK</button>
<button class="btn btn-warning" type="button" ng-click="close()">Cancel</button>
</div>
</script>
</body>
</html>
Actually I have found the issue in 'my' code. After closing the modal, it was retrieving data that caused the property bound to the select to refresh as well.
Angular Bootstrap modal Doesn't save the state when the it's closed. You must perform some alternative code to save the user state when they closed the browser or store it in cookie. After that when the user open again the modal you must fetch it and display it in your
<select....... ng-change="openSomeDialog()">...</select>

AngulaJS ng-options initially selected value from an

I have an object with property: value structure with should be used for the ng-options to create the select dropdown. I also have a ng-model variable which contains the property which should be currently selected. The problem is that I can't figure out how to fix the initial selection.
You can find the code here
<select ng-model="selectedCar" ng-options="id as value for (id, value) in cars track by id">
http://jsbin.com/wukanenozu/1/edit?html,js,output
Do not use "track by"
Do not use as and track by in the same expression. They are not
designed to work together.
<select ng-model="selectedCar" ng-options="id as value for (id, value) in cars ">
</select>
DEMO
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.cars = {
frd : "Ford",
ft1 : "Fiat",
vlv : "Volvo"
}
$scope.selectedCar = 'ft1';
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<p>Select a car:</p>
<select ng-model="selectedCar" ng-options="id as value for (id, value) in cars ">
</select>
<h1>You selected model: {{selectedCar}}</h1>
</div>
<p>This example demonstrates the use of an object as the data source when creating a dropdown list.</p>
</body>
</html>

Default value given in ng-model is not selected in drop down

I was trying simple select drop down in my app. Where I have set a default value in ng-model. But on load the drop down does not select the ng-model value.
Below are my codes:
HTML:
View <select ng-model="viewby" ng-change="setItemsPerPage(viewby)"><option>3</option><option>5</option><option>10</option><option>20</option><option>30</option><option>40</option><option>50</option></select> records at a time.
Js:
$scope.viewby=3
$scope.setItemsPerPage = function(num) {
console.log( num);
}
Here ng-change is working perfectly.
Here '3' should be selected on load. I tried ng-init and selected='selected' also and both are not working. Any suggestion will help.--thanks
Try like below snippet. Here default selected option was 20, you can change it to your need.
var app = angular.module('app', []);
app.controller("ctrl", function($scope) {
$scope.selectedOption = 20;
$scope.setItemsPerPage = function(num) {
console.log(num);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrl">
View
<select ng-model="selectedOption" ng-change="setItemsPerPage(selectedOption)">
<option>3</option>
<option>5</option>
<option>10</option>
<option>20</option>
<option>30</option>
<option>40</option>
<option>50</option>
</select>
records at a time.
</div>
</div>
In angular, Better way is to define the options as array and bind them, so that ng-model will get updated.
JS:
$scope.model = 30;
$scope.options = [10, 20, 30,40,50];
HTML
<select ng-change="setItemsPerPage(model)" ng-model="model" ng-options="value for value in options"></select>
DEMO

angularjs checkbox ng-checked not working

I have the following code :-
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script>
</head>
<body ng-app="app" ng-controller="ctrl" ng-init="init()">
<div class="container" style="width:400px">
<div class="panel panel-default">
<div class="panel-body">
<form>
<div class="form-group">
<label for="selectedBasket">Select basket :</label>
<select id="selectedBasket" class="form-control" ng-model="selectedBasket" ng-options="b.name for b in baskets">
</select>
</div>
<div ng-repeat="f in fruits" class="checkbox">
<label>
<input type="checkbox" value="" ng-checked="selectedBasket !== null && selectedBasket.items.indexOf(f) !== -1">
{{ f }}
</label>
</div>
</form>
</div>
</div>
</div>
<script>
var app = angular.module('app', []);
app.controller('ctrl', function($scope) {
$scope.init = function() {
$scope.baskets = [{'name': 'mary', 'items': ['apple', 'orange']}, {'name': 'jane', 'items': ['banana']}];
$scope.fruits = ['apple', 'banana', 'cherry', 'orange', 'watermelon'];
$scope.selectedBasket = null;
};
});
</script>
</body>
</html>
if I select Mary or Jane, I can correctly see the correct items in their basket checked. However if I manually check all the fruits and then look at Mary or Jane, it doesn't exclude the items that are not in their baskets. Why is ng-checked failing?
Bonus question, is it best practise to set selectedBasket to null and checking for null in a directive assuming I want nothing as a default value, is there a better way?
You've got no ng-model in your checkbox so your manual action isn't registered anywhere.
ng-checked is only used to make a 'slave' checkbox it can take no manual action.
My guess is you should use a ng-model initialized to your ng-check value instead of using a ng-checked.
If you want to keep your ng-checked what you can do is :
<input type="checkbox" ng-click="selectedBasket.items.push(f)" ng-checked="selectedBasket !== null && selectedBasket.items.indexOf(f) !== -1">
in fact it's still wrong... must be tired, use a toogle function in your ng-click which add or remove the item should be better...
Had the same problem with ng-check, tried everything but nothing worked. I wanted to control the number of checked Items when clicked to 2, so I used the $Event sent with ng-click and disable it.
Here is a sample code:
<input type="checkbox" ng-click="toggleCheck($event, product._id);"
ng-checked="isChecked(product._id)">
$scope.toggleCheck($event, productId){
if ( $scope.featuredProducts.indexOf(productId) === -1) {
if ($scope.featuredProducts.length < 2) {
$scope.featuredProducts.push(productId);
}else {
$event.preventDefault();
$event.stopPropagation();
}
} else {
$scope.featuredProducts.splice( $scope.featuredProducts.indexOf(productId), 1);
}
}
$scope.isChecked(productId){
return ($scope.featuredProducts.indexOf(productId) !== -1);
}

how to make dropdown with input field in angular.js

i am making dropdown list with input field in angular.js but got no success
the code which i using..
<div ng-app="" ng-controller="namesCtrl">
<h2>filter input</h2>
<input type="text" ng-model="test"/>
<ul>
<li ng-repeat="x in names | filter:test | orderBy : 'name'">
{{ x.name + ',' + x.country }}
</li>
</ul>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.firstName= "";
$scope.lastName= "";
});
</script>
<script src="namescontrol.js"></script>
Check the working demo: JSFiddle.
Use a customized filter to perform the filtering. Since ng-model binds to the value key. Whenever key is changed, the items will be filtered and the view will be changed.
angular.module('Joy',[])
.controller('JoyCtrl', ['$scope', function ($scope) {
$scope.items = ['one', 'two', 'three', 'four', 'five'];
$scope.key = '';
$scope.search = function (value) {
return value.indexOf($scope.key) >= 0;
}
}]);
HTML:
<div ng-app="Joy" ng-controller="JoyCtrl">
<input type="text" ng-model="key">
<div>
<li ng-repeat="item in (items | filter:search)" ng-bind="item"></li>
</div>
</div>
Update 1
If you want to hide the list initially: JSFiddle:
$scope.search = function (value) {
return $scope.key !== '' && value.indexOf($scope.key) >= 0;
};
Update 2
I have developed an open source project angular-sui based on Angular and Semantic-UI. There is a directive sui-select, which is exactly what you want. Please check the Demo.
I think what you are looking for is autocomplete functionality. AngularUI offers this through their Typeahead directive. https://angular-ui.github.io/bootstrap/#/typeahead
You want to have something like this:
<input type="text" ng-model="test" typeahead="name for name in names"/>
The directive will dynamically generate the list so you don't need to create that explicitly yourself.

Resources