How to use bootstrap-select with angular - angularjs

I would like to style my dropdowns with bootstrap-select.
There are two dropdowns in the page. The first one has hardcoded options. The second one is bound dynamically with data from database.
The bootstrap-select is applied all well for the first one but not the second. It adds a text 'Nothing selected' and the options also are not bound.
How to fix this.
aspx:
<link href="../assets/css/bootstrap-select.css" rel="stylesheet" />
<script src="../assets/js/bootstrap-select.js"></script>
<script src="../assets/js/angular-1.3.16.min.js"></script>
<script src="../scripts/app.js"></script>
<script src="../scripts/controllers/Ctrl.js"></script>
<script src="../scripts/services/Factory.js"></script>
<script src="../scripts/directives/directives.js"></script>
<select id="ddlReports" bootstrapselectpicker >
<option data-ng-repeat="item in Reports" value="{{item.Id}}">{{item.Name}}</option>
</select>
<select id="ddlSets" bootstrapselectpicker>
<option value="0">-- Select Question Set --</option>
<option data-ng-repeat="item in QuestionSets" value="{{item.SetId}}">{{item.Title}}</option>
</select>
Ctrl.js
app.controller("Ctrl", ["$scope", "Factory", function ($scope, Factory) {
var init = function() {
$scope.Reports = [
{ Id: 1, Name: "abc" },
{ Id: 2, Name: "def" }
];
var promise = Factory.GetData();
promise.then(function (success) {
if (success.data != null && success.data != '') {
var data = success.data;
$scope.QuestionSets = data.QuestionSets;
}
},
function (error) {
});
}
init();
}]);
directive.js
app.directive('bootstrapselectpicker', function ($timeout) {
return {
restrict: "A",
link: function (scope, element, attrs, ctrl) {
$timeout(function () {
element.selectpicker();
});
}
};
});

Related

Dynamically update ion.rangeSlider ngModel in AngularJS directive

I'm trying to update the value of an Ion.RangeSlider when its bound ng-model scope variable changes. The model updates when the Ion.RangeSlider is used, but not vice-versa. Other inputs with the same ng-model update when the model value changes, so this must be some special case.
Edit: Woo! Here's a snippet #lin :) Also jsfiddle.
var app = angular.module('ngModelIonRangeSliderDemo', []);
app.controller('MainCtrl', function ($scope, $rootScope, $timeout) {
$scope.someNumber = 10;
}).directive('ionRangeSlider', function ionRangeSlider() {
return {
restrict: 'A',
scope: {
rangeOptions: '=',
model: '=ngModel'
},
link: function (scope, elem, attrs) {
scope.$watch('model',function () {
elem.ionRangeSlider(scope.rangeOptions);
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.10/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.1.2/ui-bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/js/ion.rangeSlider.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/css/ion.rangeSlider.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/css/ion.rangeSlider.skinFlat.min.css" />
<div ng-app="ngModelIonRangeSliderDemo">
<div ng-controller="MainCtrl" class="wrapper">
<h3>Text input updates slider, but not vice-versa.</h3>
<input ion-range-slider ng-model="someNumber" range-options="{min: -100, max: 100, step: .001}">
<br/>
<input type="text" ng-model="someNumber" class="form-control">
</div>
</div>
I have tried all kinds of suggestions in over ten somewhat-related stack overflow posts (which is how I have set up the current scope.$watch scheme on the ngModel), but none have worked. There aren't any errors in my console. What's wrong? Also, why doesn't it work without any mention of the model in my directive? Please let me know if there's anything important I have failed to include in this post.
Just use slider.update() inside your directive and you will be fine:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function ($scope, $rootScope, $timeout) {
$scope.someNumber = 15;
$scope.apply = false;
}).directive('ionRangeSlider', function ionRangeSlider() {
return {
restrict: 'A',
scope: {
rangeOptions: '=',
model: '=ngModel',
apply: '=apply'
},
link: function (scope, elem, attrs) {
elem.ionRangeSlider(scope.rangeOptions);
scope.$watch('apply',function () {
if (scope.apply) {
scope.apply = false;
var slider = elem.data("ionRangeSlider");
slider.update({
from: scope.model
});
}
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.10/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.1.2/ui-bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/js/ion.rangeSlider.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/css/ion.rangeSlider.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/css/ion.rangeSlider.skinFlat.min.css" />
<div ng-app="myApp" ng-controller="MainCtrl" class="wrapper">
<h3>Text input updates slider and vice-versa.</h3>
<input ion-range-slider ng-model="someNumber" apply="apply" range-options="{min: -100, max: 100, step: .001}">
<br/>
<input type="text" ng-model="someNumber" class="form-control" ng-change="apply = true">
</div>
Extra demo, how binding ion.rangeSlider to input works:
http://jsfiddle.net/IonDen/r5aox84v/
var $range = $(".js-range-slider"),
$inputFrom = $(".js-input-from"),
$inputTo = $(".js-input-to"),
instance,
min = 0,
max = 1000,
from = 0,
to = 0;
$range.ionRangeSlider({
type: "double",
min: min,
max: max,
from: 200,
to: 800,
onStart: updateInputs,
onChange: updateInputs
});
instance = $range.data("ionRangeSlider");
function updateInputs (data) {
from = data.from;
to = data.to;
$inputFrom.prop("value", from);
$inputTo.prop("value", to);
}
$inputFrom.on("input", function () {
var val = $(this).prop("value");
// validate
if (val < min) {
val = min;
} else if (val > to) {
val = to;
}
instance.update({
from: val
});
});
$inputTo.on("input", function () {
var val = $(this).prop("value");
// validate
if (val < from) {
val = from;
} else if (val > max) {
val = max;
}
instance.update({
to: val
});
});

Merge two examples in Angularjs

I am trying to build #TagFriends and comment box feature from FACEBOOK.
I found two examples that might help, I am having library issue when I import one examples library in second one, whole code fails to work, if they are executed individually they work correctly.
1.Simple comment box :
http://devzone.co.in/angularjs-example-simple-user-comment-box/
2.#Tag friend code Below:
<!DOCTYPE html>
<html>
<head>
<link data-require="bootstrap#*" data-semver="3.3.2" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
<link rel="stylesheet" href="http://urbanoalvarez.es/smart-area/dist/smart-area.css">
<script data-require="jquery#2.1.3" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<script data-require="bootstrap#*" data-semver="3.3.2" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script data-require="angular.js#1.3.8" data-semver="1.3.8" src="https://code.angularjs.org/1.3.8/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular-sanitize.js"></script>
<script src="http://urbanoalvarez.es/smart-area/dist/smart-area.js"></script>
<script src="elastic.js"></script>
<script src="app.js"></script>
<style>
.user{
color: #0074D9;
}
</style>
</head>
<body ng-app="myApp">
<div class="container" ng-controller="DemoController">
<h3>MOC 12</h3>
<!--<h4>#user mentions</h4>-->
<textarea class="form-control code" rows="5" ng-model="text" ng-trim="false" msd-elastic smart-area="config"></textarea>
<hr>
<small class="text-muted">
<b>Available users:</b><br> Bret, Antonette, Samantha, Karianne, Kamren, Leopoldo_Corkery, Elwyn.Skiles, Delphine, Maxime_Nienow, Moriah.Stanton <br>
Type for example "Hey #Antonette"
</div>
<script>
/*
* angular-elastic v2.4.2
* (c) 2014 Monospaced http://monospaced.com
* License: MIT
*/
angular.module('myApp', ['smartArea', 'monospaced.elastic'])
.controller('DemoController', ['$scope', '$http', function($scope, $http) {
$scope.text = '';
$scope.config = {
autocomplete: [
{
words: [/#([A-Za-z]+[_A-Za-z0-9]+)/gi],
cssClass: 'user'
}
],
dropdown: [
{
trigger: /#([A-Za-z]+[_A-Za-z0-9]+)/gi,
list: function(match, callback){
// match is the regexp return, in this case it returns
// [0] the full match, [1] the first capture group => username
$http.get('http://jsonplaceholder.typicode.com/users')
.success(function(data){
// Prepare the fake data
var listData = data.filter(function(element){
return element.username.substr(0,match[1].length).toLowerCase() === match[1].toLowerCase()
&& element.username.length > match[1].length;
}).map(function(element){
return {
display: element.username, // This gets displayed in the dropdown
item: element // This will get passed to onSelect
};
});
callback(listData);
}).error(function(err){
console.error(err);
});
},
onSelect: function(item){
return item.display;
},
mode: 'replace'
}
]
};
}]);
angular.module('monospaced.elastic', [])
.constant('msdElasticConfig', {
append: ''
})
.directive('msdElastic', [
'$timeout', '$window', 'msdElasticConfig',
function($timeout, $window, config) {
'use strict';
return {
require: 'ngModel',
restrict: 'A, C',
link: function(scope, element, attrs, ngModel) {
// cache a reference to the DOM element
var ta = element[0],
$ta = element;
// ensure the element is a textarea, and browser is capable
if (ta.nodeName !== 'TEXTAREA' || !$window.getComputedStyle) {
return;
}
// set these properties before measuring dimensions
$ta.css({
'overflow': 'hidden',
'overflow-y': 'hidden',
'word-wrap': 'break-word'
});
// force text reflow
var text = ta.value;
ta.value = '';
ta.value = text;
// exit if elastic already applied (or is the mirror element)
if ($ta.data('elastic')) {
return;
}
// Opera returns max-height of -1 if not set
maxHeight = maxHeight && maxHeight > 0 ? maxHeight : 9e4;
// append mirror to the DOM
if (mirror.parentNode !== document.body) {
angular.element(document.body).append(mirror);
}
// set resize and apply elastic
$ta.css({
'resize': (resize === 'none' || resize === 'vertical') ? 'none' : 'horizontal'
}).data('elastic', true);
/*
* methods
*/
/*
* initialise
*/
// listen
if ('onpropertychange' in ta && 'oninput' in ta) {
// IE9
ta['oninput'] = ta.onkeyup = adjust;
} else {
ta['oninput'] = adjust;
}
$win.bind('resize', forceAdjust);
scope.$watch(function() {
return ngModel.$modelValue;
}, function(newValue) {
forceAdjust();
});
scope.$on('elastic:adjust', function() {
initMirror();
forceAdjust();
});
$timeout(adjust);
/*
* destroy
*/
scope.$on('$destroy', function() {
$mirror.remove();
$win.unbind('resize', forceAdjust);
});
}
};
}
]);
</script>
</body>
</html>
I have implemented this feature. Find the GitHub: github.com/noob93/Smart-Comment-Box
The Devzone example is using a deprecated feature of AngularJs, I modified the code and feature started working fine.

Focus is not working by index in AngularJS

I have a list of items which have update text field with some words, I want to get the focus at end of the words on the selected index. but every time I am getting focus on last index.
Here is my HTML code
<body ng-controller="MainCtrl">
<h1>Hello Plunker!</h1>
<li ng-repeat="i in number">
<input focus-on="focusMe" value="sfsfsf" />
<button type="submit" ng-click="do()">do</button>
</li>
</body>
Here my controller:
app.directive('focusOn', function() {
return function(scope, elem, attr) {
scope.$on('focusOn', function(e, name) {
if(name === attr.focusOn) {
elem[0].focus();
}
});
};
});
app.factory('focus', function ($rootScope, $timeout) {
return function(name) {
$timeout(function (){
$rootScope.$broadcast('focusOn', name);
});
}
});
app.controller('MainCtrl', function ($scope, focus) {
$scope.number=[1,2,3,4,5,6,7,8,9,10];
$scope.do=function(){
focus('focusMe');
}
Here is my plunker.
Correct solution will probably depend on what browsers you need to support.
You can try this:
scope.$on('focusOn', function(e, name) {
if (name == attr.name) {
var element = elem[0];
element.focus();
var value = element.value;
element.value = '';
element.value = value;
}
});
Demo: http://plnkr.co/edit/pulIrU56qf2J4UjCJlgQ?p=preview

Mithril with angularjs

I am a newbie to Mithril JS framework and trying to integrate Mitril view with angularJS. Has anyone tried this before?
I want to check how can we bind the angular controller methods to click events of elements created in Mitril.
I got this working by having this code
var e = document.getElementById('elementId');
var scope = angular.element(e).scope();
m("a[href='javascript:;']", {
onclick : scope.someMethod
}, "Test");
But I am not sure if this is right way to do this.
I'd say that is not idiomatic angular code.
A more idiomatic way might be to use a directive on the Angular side, and pass in an event dispatcher controller to the view on the mithril side:
//mithril code
var testWidget = function(ctrl) {
return m("a[href='javascript:;']", {onclick: ctrl.onclick}, "Test")
}
//angular code
angular.module("foo").directive("testWidget", function() {
return {
restrict: "E",
link: function($scope, element, attrs) {
var template = testWidget({
onclick: function() {
$scope.$apply(function() {
$scope.$eval(attrs.onclick)
})
}
})
m.render(element, template)
}
}
})
angular.module("foo").controller("MyCtrl", function() {
this.doStuff = function() {
console.log("called doStuff")
}
})
<div ng-controller="MyCtrl as c">
<test-widget onclick="c.doStuff()"></test-widget>
</div>
// Code goes here
(function() {
'use strict';
angular
.module('app', [])
.directive('testMithrilScope', testMithrilScope)
.controller('MyCtrl', MyCtrl);
var testMithrilWidgetScope = function(ctrl) {
return m("a[href='javascript:;']", {onclick: ctrl.directiveclick}, ctrl.text)
}
var htmllinks = [
{text: "Link 1 "},
{text: "Link 2 "},
{text: "Link 3 "},
{text: "Link 4 "},
{text: "Link 5 "},
{text: "Link 6 "}
];
function testMithrilScope() {
return {
restrict: "E",
scope : {
htmlclick: '&'
},
link: function($scope, element, attrs) {
function makeList1() {
return m('ul', htmllinks.map(function(a, index){
return m('li', testMithrilWidgetScope({
directiveclick : function() {
var data = {
arg1: a.text
}
$scope.htmlclick(data);
},
text : a.text
})
);
}));
}
var template1 = makeList1();
m.render(element[0], template1)
}
}
}
function MyCtrl() {
this.doStuff = function(text) {
console.log("You clicked: " + text)
}
}
})();
<!DOCTYPE html>
<html>
<head>
<script data-require="angularjs#1.5.8" data-semver="1.5.8" src="https://opensource.keycdn.com/angularjs/1.5.8/angular.min.js"></script>
<script data-require="mithril#0.2.4" data-semver="0.2.4" src="https://cdn.jsdelivr.net/mithril/0.2.4/mithril.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app">
<div ng-controller="MyCtrl as ctrl">
<test-mithril-scope htmlclick="ctrl.doStuff(arg1)"></test-mithril-scope>
</div>
</body>
</html>

ng-options with disabled rows

Is it possible to use ng-options that it will render into disabled rows based on criteria?
this:
<select ng-options="c.name group by c.shade for c in colors">
maybe possible to turn into something like this:
<select ng-options="c.name group by c.shade for c in colors | disabled(c.shade)">
and let's say via a filter that could return disabled='disabled' for all the colors that have shade = "dark"
<select>
<optgroup label="dark">
<option value="0" disabled="disabled">black</option>
<option value="2" disabled="disabled">red</option>
<option value="3" disabled="disabled">blue</option>
</optgroup>
<optgroup label="light">
<option value="1">white</option>
<option value="4">yellow</option>
</optgroup>
</select>
#lucuma's answer (originally the accepted answer) was correct, but by now should be updated, because this was fixed in Angular 1.4. See the docs of ng-options which also contains an example.
I'm using Angular 1.5 and this works for me:
View
<select ng-model="$ctrl.selectedItem" ng-options="item as item.label disable when item.disabled for item in $ctrl.listItems">
Controller
vm.items = [
{ id: 'optionA', label: 'Option A' },
{ id: 'optionB', label: 'Option B (recommended)' },
{ id: 'optionC', label: 'Option C (Later)', disabled: true }
];
vm.selectedItem = vm.items[1];
As pointed by #Lod Angular added support for this in 1.4.0-beta.5.
For angular js >= 1.4.0-beta.5.
<select ng-options="c.name disable when c.shade == 'dark'
group by c.shade for c in colors">
And for angular js < 1.4.0-beta.5 refer the solution below:
Similar to the one given by #lucuma but without jQuery dependency.
Check this http://jsfiddle.net/dZDLg/46/
Controller
<div ng-controller="OptionsController">
<select ng-model="selectedport"
ng-options="p.name as p.name for p in ports"
options-disabled="p.isinuse for p in ports"></select>
<input ng-model="selectedport">
</div>
Directive
angular.module('myApp', [])
.directive('optionsDisabled', function($parse) {
var disableOptions = function(scope, attr, element, data,
fnDisableIfTrue) {
// refresh the disabled options in the select element.
var options = element.find("option");
for(var pos= 0,index=0;pos<options.length;pos++){
var elem = angular.element(options[pos]);
if(elem.val()!=""){
var locals = {};
locals[attr] = data[index];
elem.attr("disabled", fnDisableIfTrue(scope, locals));
index++;
}
}
};
return {
priority: 0,
require: 'ngModel',
link: function(scope, iElement, iAttrs, ctrl) {
// parse expression and build array of disabled options
var expElements = iAttrs.optionsDisabled.match(
/^\s*(.+)\s+for\s+(.+)\s+in\s+(.+)?\s*/);
var attrToWatch = expElements[3];
var fnDisableIfTrue = $parse(expElements[1]);
scope.$watch(attrToWatch, function(newValue, oldValue) {
if(newValue)
disableOptions(scope, expElements[2], iElement,
newValue, fnDisableIfTrue);
}, true);
// handle model updates properly
scope.$watch(iAttrs.ngModel, function(newValue, oldValue) {
var disOptions = $parse(attrToWatch)(scope);
if(newValue)
disableOptions(scope, expElements[2], iElement,
disOptions, fnDisableIfTrue);
});
}
};
});
Note: This solution doesn't work with group by as rightly pointed by everyone. Refer the solution below by #DHlavaty if you are looking to make it work with group by.
Angular added support for this in 1.4.0-beta.5
<select ng-options="c.name disable when c.shade == 'dark' group by c.shade for c in colors">
I do not believe there is a way to do what you are asking just using ng-options. This issue was raised on the angular project and is still open:
https://github.com/angular/angular.js/issues/638
It seems that the work around is to use a directive which is referenced here and in the github issue: http://jsfiddle.net/alalonde/dZDLg/9/
Here is the entire code from the jsfiddle for reference (the code below is from alande's jsfiddle):
<div ng-controller="OptionsController">
<select ng-model="selectedport"
ng-options="p.name as p.name for p in ports"
options-disabled="p.isinuse for p in ports"></select>
<input ng-model="selectedport">
</div>
angular.module('myApp', [])
.directive('optionsDisabled', function($parse) {
var disableOptions = function(scope, attr, element, data, fnDisableIfTrue) {
// refresh the disabled options in the select element.
$("option[value!='?']", element).each(function(i, e) {
var locals = {};
locals[attr] = data[i];
$(this).attr("disabled", fnDisableIfTrue(scope, locals));
});
};
return {
priority: 0,
require: 'ngModel',
link: function(scope, iElement, iAttrs, ctrl) {
// parse expression and build array of disabled options
var expElements = iAttrs.optionsDisabled.match(/^\s*(.+)\s+for\s+(.+)\s+in\s+(.+)?\s*/);
var attrToWatch = expElements[3];
var fnDisableIfTrue = $parse(expElements[1]);
scope.$watch(attrToWatch, function(newValue, oldValue) {
if(newValue)
disableOptions(scope, expElements[2], iElement, newValue, fnDisableIfTrue);
}, true);
// handle model updates properly
scope.$watch(iAttrs.ngModel, function(newValue, oldValue) {
var disOptions = $parse(attrToWatch)(scope);
if(newValue)
disableOptions(scope, expElements[2], iElement, disOptions, fnDisableIfTrue);
});
}
};
});
function OptionsController($scope) {
$scope.ports = [{name: 'http', isinuse: true},
{name: 'test', isinuse: false}];
$scope.selectedport = 'test';
}
A similar effect can be achieved using ng-repeat and ng-disabled on the option itself, avoiding the use of a new directive.
HTML
<div ng-controller="ExampleController">
<select ng-model="myColor">
<option ng-repeat="c in colors" ng-disabled="c.shade=='dark'" value="{{$index}}">
{{c.name}}
</option>
</select>
</div>
Controller
function ExampleController($scope, $timeout) {
$scope.colors = [
{name:'black', shade:'dark'},
{name:'white', shade:'light'},
{name:'red', shade:'dark'},
{name:'blue', shade:'dark'},
{name:'yellow', shade:'light'}
];
$timeout(function() {
$scope.myColor = 4; // Yellow
});
}
Fiddle
http://jsfiddle.net/0p4q3b3s/
Known issues:
Does not use ng-options
Does not work with group by
Selects the index, not the object
Requires $timeout for initial selection
Edit :
Any object property can be selected (besides the index), but not the object itself. Also, if you have a simple array and not an array of objects, below method will work.
Change this line in HTML :
<option ng-repeat="c in colors" ng-disabled="c.shade=='dark'" value="{{c.name}}">
Change this line in Controller :
$scope.myColor = $scope.colors[4].name; // Yellow
Since February 2015 there has been a way to disable options in your ng-options tag.
This Link shows the addition of the feature on github
I found that using angular 1.4.7, the syntax had changed from 'disable by' to 'disable when'.
The syntax for this is:
'ng-options': 'o.value as o.name disable when o.unavailable for o in options'
I had an interesting situation. An array of dropdowns and I need it to disable the options that were already selected in each of the dropdowns, but I also need it to keep enable the one that was selected already...
here is my plunker: Enable/Disable values with ng-options
var app = angular.module('ngoptions', []);
app.controller('MainCtrl', function($scope) {
// disable the fields by default
$scope.coverage = [
{ CoverageType: '', CoverageName: 'No Coverage' },
{ CoverageType: 'A', CoverageName: 'Dependent Only' },
{ CoverageType: 'B', CoverageName: 'Employee Plus Children' },
{ CoverageType: 'C', CoverageName: 'Employee Only' },
{ CoverageType: 'D', CoverageName: 'Employee Plus One' },
{ CoverageType: 'E', CoverageName: 'Employee Plus Two' },
{ CoverageType: 'F', CoverageName: 'Family' },
];
// values already set ex: pulled from db
$scope.rates = ['A','C', 'F'];
$scope.changeSelection = function (index, rate){
$scope.rates[index] = rate;
disableRecords();
}
// start by disabling records
disableRecords();
function disableRecords () {
// set default values to false
angular.forEach($scope.coverage, function (i, x) {
i.disable = false;
});
// set values to true if they exist in the array
angular.forEach($scope.rates, function (item, idx) {
angular.forEach($scope.coverage, function (i, x) {
if (item == i.CoverageType) {
i.disable = true;
}
});
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script>
<!DOCTYPE html>
<html ng-app="ngoptions">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script data-require="angular.js#1.4.7" data-semver="1.4.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<table>
<thead></thead>
<tbody>
<tr ng-repeat="rate in rates">
<td>
<select
ng-model="rate"
ng-change="changeSelection($index, rate)"
ng-options="type.CoverageType as type.CoverageName disable when (type.disable == true && type.CoverageType != rate) for type in coverage"></select>
</td>
</tr>
</tbody>
</table>
</body>
</html>
You can disable using ngOptions in angular 1.4.1 or above
HTML template
<div ng-app="myapp">
<form ng-controller="ctrl">
<select id="t1" ng-model="curval" ng-options='reportingType.code as reportingType.itemVal disable when reportingType.disable for reportingType in reportingOptions'>
<option value="">Select Report Type</option>
</select>
</form>
Controller code
angular.module('myapp',[]).controller("ctrl", function($scope){
$scope.reportingOptions=[{'code':'text','itemVal':'TEXT','disable':false}, {'code':'csv','itemVal':'CSV','disable':true}, {'code':'pdf','itemVal':'PDF','disable':false}];
})
Similar "without jQuery" solution as #Vikas-Gulati's, but it works with group by
In my case, group by doesn't work, because my first <option> was without value, just with Please select and item from dropdown text. This is a slightly modified version, that fixes this particular situation:
Usage is simmilar to #Vikas-Gulati answer: https://stackoverflow.com/a/20790905/1268533
Directive
angular.module('disabledModule', [])
.directive('optionsDisabled', function($parse) {
var disableOptions = function(scope, attr, element, data, fnDisableIfTrue) {
var realIndex = 0;
angular.forEach(element.find("option"), function(value, index){
var elem = angular.element(value);
if(elem.val()!="") {
var locals = {};
locals[attr] = data[realIndex];
realIndex++; // this skips data[index] with empty value (IE first <option> with 'Please select from dropdown' item)
elem.attr("disabled", fnDisableIfTrue(scope, locals));
}
});
};
return {
priority: 0,
require: 'ngModel',
link: function(scope, iElement, iAttrs, ctrl) {
// parse expression and build array of disabled options
var expElements = iAttrs.optionsDisabled.match(/^\s*(.+)\s+for\s+(.+)\s+in\s+(.+)?\s*/);
var attrToWatch = expElements[3];
var fnDisableIfTrue = $parse(expElements[1]);
scope.$watch(attrToWatch, function(newValue, oldValue) {
if(newValue)
disableOptions(scope, expElements[2], iElement, newValue, fnDisableIfTrue);
}, true);
// handle model updates properly
scope.$watch(iAttrs.ngModel, function(newValue, oldValue) {
var disOptions = $parse(attrToWatch)(scope);
if(newValue)
disableOptions(scope, expElements[2], iElement, disOptions, fnDisableIfTrue);
});
}
};
});
As I cannot upgrade to latest angularJS, so created a simpler directive to handle it.
.directive('allowDisabledOptions',['$timeout', function($timeout) {
return function(scope, element, attrs) {
var ele = element;
var scopeObj = attrs.allowDisabledOptions;
$timeout(function(){
var DS = ele.scope()[scopeObj];
var options = ele.children();
for(var i=0;i<DS.length;i++) {
if(!DS[i].enabled) {
options.eq(i).attr('disabled', 'disabled');
}
}
});
}
}])
for more details: https://github.com/farazshuja/disabled-options
I also hid disabled options adding fallowing line:
$(this).css("display", fnDisableIfTrue(scope, locals) ? "none" : "block");
It was necessary as I couldn't simply filter them out, as the initial value of this select could be one of the disabled options.

Resources