Using Bootstrap-select with AngularJS - angularjs

I am trying to implement http://silviomoreto.github.io/bootstrap-select/ to my AngularJS application.
Most of the people who try and do the same, they have any issue that the selectpicker is set before Angular gets the data. But for me that is not the case. When Select Picker is fired, my select has all the data but for some reason the dropdown toggle event is not firing.
HTML:
<select id="partyRole" name="partyRole" class="form-control" ng-model="partyRole" ng-options="role as role.text for role in partyRoles">
<option value="">Please Select...</option>
</select>
The JS calls adds selectpicker to all my selects.
JS:
$(window).bind("load", function () {
return $('select').selectpicker();
});
I am also using this directive to bind the selectpicker data:
https://github.com/joaoneto/angular-bootstrap-select/blob/master/build/angular-bootstrap-select.js
Final UI
As you can see the div gets created from the selectpicker and I also get all the data.. But clicking on the button does nothing.
I have Angular UI, Angular JS in the application with Bootstrap stylesheets.
EDIT:
Nevermind, the version of the angular directive I downloaded from github was probably in a broken state, because after I applied it from today's updated code.. it worked.

You don't want to have have some jQuery in a file and some AngularJS in another file, usually. If jQuery creates elements etc, they probably won't be picked up by angular.
The correct solution is to use an Angular directive. Here, it looks like somebody made one for you.

function Selectpicker() {
return {
restrict: 'C',
link: function($scope, $element) {
$element.selectpicker();
}
};
}

Related

How to invoke a JQuery method after Angular select directive applies a model change?

I am trying to change the selection of David Stutz's bootstrap-multiselect via Angular ng-model:
<select ng-model="selection" multiple="multiple" id="my-example">
<option value="cheese">Cheese</option>
<option value="tomatoes">Tomatoes</option>
<option value="mozarella">Mozzarella</option>
<option value="mushrooms">Mushrooms</option>
<option value="pepperoni">Pepperoni</option>
<option value="onions">Onions</option>
</select>
The changes to the model only get applied to the underlying select element, but the bootstrap-multiselect doesn't get updated automatically. Looking at its documentation, this is expected: you are required to call multiselect('refresh') afterwards to propagate the changes:
$('#my-example').multiselect('refresh');
My question is:
How to invoke this method when the model changes after Angular is done updating the select element?
Since I need to access the element, I assume directives are the way to go. I was looking at decorators, which in theory I could use to modify the behavior of the built-in select directive, but I don't know how to get my code invoked at the right moment.
I've prepared a plunk to demo the issue:
I have two multiselects bound to the same model: a bootstrap-multiselect and a plain one
I initialize both with a default selection
The first button changes the selection. The plain multiselect is updated immediatelly, but the bootstrap-multiselect appears unchanged.
The second button shows the current model value in an alert.
The third button calls refresh on bootstrap-multiselect, which causes it to update. This is what I would like to get called automatically by Angular.
In the end I managed to solve my problem with a decorator. I based it on the Directive Decorator Example in AngularJS documentation.
Unlike ngHrefDirective from the example, selectDirective defines both preLink and postLink, therefore the compile override must also return both. I only needed to change postLink though, where $render is defined. In my version of the method I simply invoked the original method, which updates the select element, and called multiselect('refresh') afterwards, which was my original requirement:
app.config(['$provide', function($provide) {
$provide.decorator('selectDirective', ['$delegate', function($delegate) {
var directive = $delegate[0];
directive.compile = function() {
function post(scope, element, attrs, ctrls) {
directive.link.post.apply(this, arguments);
var ngModelController = ctrls[1];
if (ngModelController) {
originalRender = ngModelController.$render;
ngModelController.$render = function() {
originalRender();
element.multiselect('refresh');
};
}
}
return {
pre: directive.link.pre,
post: post
};
};
return $delegate;
}]);
}]);
I dont think you should mix that (why refresh data with jquery while the data is in angular's watch cycle?). You can do something like this with your options:
<option ng-value="Cheese.val">{{Cheese.text}}</option>
<option ng-value="Tomatoes.val">{{Tomatoes.text}}</option>
And handle the rest with Angular (maybe google for angular + multiselect)

AngularJs watch angular.element

I'm trying to integrate AngularJs into a legacy Spring MVC application because there is lots of spaghetti javascript code (a huge mess!) to hide / show html elements based on conditions etc.
It uses jsp and lots of custom jsp tags and because the way it is written I'm hesitant to mess with the jsp tags themselves.
I'm trying to do is read the values of the spring input into angular scope and once I have it then can use angular to hide / show stuff.
Assume that my html is something like this
<div ng-app ng-controller="FooCtrl">
Backbone <input type="radio" name="yes" value="Backbone"/>
Angular <input type="radio" name="yes" value="Angular" />
</div>
I'm able to read these elements into Angular's scope like this
$scope.elements = angular.element("input[name='yes']");
But change to the value of these elements are not getting triggered or watched by Angular.
Ideally when the radio button gets checked I would like the model to change. How can I do this?
Thank you in advance.
Here is plnkr with the basic setup.
http://plnkr.co/edit/CRPBFF9FaGivBRa8OSdZ?p=preview
One thing is that in your controller you had:
$scope.$watch('$scope.elements',function(newValue){
console.log(newValue);
},true);
It should be 'elements' rather than '$scope.elements'. I'm not quite sure if a $watch or $watchCollection is going to be your best bet here. I tried it but was having issues.
Here is another idea:
var app = angular.module('myApp',[]);
app.controller('FooCtrl', function($scope){
$scope.message = "hi";
$scope.elements = angular.element("input[name='yes']");
angular.element("input[name='yes']").bind("input change", function(e) {
console.log(e);
});
});

AngularJS and Select2 model state not rendering after select box

I'm running into some kind of issue where if I have a scope variable defined, it shows before the HTML reaches the select2 box, but if I show the variable after the select2 element, it doesn't render.
Here's my HTML:
{{stateIsValid}}
<select id="state" name="state" class="select2" ng-change="stateChanged()" ng-model="client.state">
<option value="state">State...</option>
<option value="NJ">NJ</option>
</select>
{{stateIsValid}}
The JS just establishes the select2 box, and sets a scope variable:
$('.select2#state').select2();
angular.extend($scope, {
stateIsValid: false
});
My issue is, in the HTML selection, the first {{stateIsValid}} renders "false", but the second doesn't render at all and just displays {{stateIsValid}}.
I don't get any console errors.
This seems to be specifically an error with the select2 rendering itself. If I comment out the select2() initialization, then everything works fine.
I'm trying to get this working so I can show a custom error below the select box.
Any help would be appreciated!
Thanks,
Ryan
There something weird on select2 initialization method.
You can solve with a $timeout wrap.
$timeout(function() {
$('.select2#state').select2();
})
here the plunkr: http://plnkr.co/edit/i1HNAtfHfNkq2srAff5S?p=preview

Kendo Angular multiselect set selected values

I´m using Kendo multiselect with Angular-Kendo directives and with remote datasource. I´m trying to set the selected items when the application starts but with no luck. Can anyone please help me?
See Code here: JS Bin
You can just make a custom directive, and pass in the items you want selected beforehand to the value attribute of the multiselect directive, have a look at this Plunk to see the directive I use.
You have to hook into the on change event directive and send the kendoEvent. Then you can use the supported kendo methods on e.sender. Check it out on this plunker
<select id="required" multiple="multiple" kendo-multi-select k-on-change="changed(kendoEvent)">
<option>Steven White</option>
<option>Nancy King</option>
<option>Nancy Davolio</option>
<option>Robert Davolio</option>
<option>Michael Leverling</option>
<option>Andrew Callahan</option>
<option>Michael Suyama</option>
<option selected>Anne King</option>
<option>Laura Peacock</option>
<option>Robert Fuller</option>
<option>Janet White</option>
<option>Nancy Leverling</option>
<option>Robert Buchanan</option>
<option>Margaret Buchanan</option>
<option selected>Andrew Fuller</option>
<option>Anne Davolio</option>
<option>Andrew Suyama</option>
<option>Nige Buchanan</option>
<option>Laura Fuller</option>
</select>
var app = angular.module('app', ['kendo.directives']);
app.controller("myCtrl", function ($compile, $scope) {
$scope.changed = function(e) {
console.log(e.sender.dataItems());
};
});

How to create this custom control with AngularJS directive?

I'm a bit new to AngularJS and am trying to write a custom select control based on Zurb Foundation's custom select(see here: http://foundation.zurb.com/docs/components/custom-forms.html)
I know I need to use a directive for this but am not sure how to accomplish this.
It's going to have to be reusable and allow for the iterating of whatever array is passed in to it. A callback when the user selects the item from the dropdown list is probably needed.
Here is the markup for the custom Foundation dropdown list:
<select name="selectedUIC" style="display:none;"></select>
<div class="custom dropdown medium" style="background-color:red;">
Please select item
<ul ng-repeat="uic in uics">
<li class="custom-select" ng-click="selectUIC(uic.Name)">{{uic.Name}}</li>
</ul>
</div>
This works for now. I am able to populate the control from this page's Ctrl. However, as you can see, I'd have to do this every time I wanted to use a custom dropdown control.
Any ideas as to how I can turn this baby into a reusable directive?
Thanks for any help!
Chris
If you want to make your directives reusable not just on the same page, but across multiple AngularJS apps, then it's pretty handy to set them up in their own module and import that module as a dependency in your app.
I took Cuong Vo's plnkr above (so initial credit goes to him) and separated it out with this approach. Now this means that if you want to create a new directive, simply add it to reusableDirectives.js and all apps that already have ['reusableDirectives'] as a dependency, will be able to use that new directive without needing to add any extra js to that particular app.
I also moved the markup for the directive into it's own html template, as it's much easy to read, edit and maintain than having it directly inside the directive as a string.
Plnkr Demo
html
<zurb-select data-label="{{'Select an option'}}" data-options="names"
data-change-callback="callback(value)"></zurb-select>
app.js
// Add reusableDirectives as a dependency in your app
angular.module('angularjs-starter', ['reusableDirectives'])
.controller('MainCtrl', ['$scope', function($scope) {
$scope.names = [{name: 'Gavin'}, {name: 'Joseph'}, {name: 'Ken'}];
$scope.callback = function(name) {
alert(name);
};
}]);
reusableDirectives.js
angular.module('reusableDirectives', [])
.directive('zurbSelect', [function(){
return {
scope: {
label: '#', // optional
changeCallback: '&',
options: '='
},
restrict: 'E',
replace: true, // optional
templateUrl: 'zurb-select.html',
link: function(scope, element, attr) { }
};
}]);
zurb-select.html
<div class="row">
<div class="large-12 columns">
<label>{{label || 'Please select'}}</label>
<select data-ng-model="zurbOptions.name" data-ng-change="changeCallback({value: zurbOptions.name})"
data-ng-options="o.name as o.name for o in options">
</select>
</div>
</div>
Is something like this what you're looking for?
http://plnkr.co/edit/wUHmLP
In the above example you can pass in two attribute parameters to your custom zurbSelect directive. Options is a list of select option objects with a name attribute and clickCallback is the function available on the controller's scope that you want the directive to invoke when a user clicks on a section.
Notice there's no code in the link function (this is where the logic for your directive would generally go). All we're doing is wrapping a template so that it's reusable and accepts some parameters.
We created an isolated scope so the directive doesn't need to depend on parent scopes. We binded the isolated scope to the attribute parameters passed in. The '&' means bind to the expression on the parent scope calling this (in our case the callback function available in our controller) and the '=' means create a two way binding between the options attribute so when it changes in the outter scope, the change is reflected here and vice versa.
We're also restricting the usage of this directive to only elements (). You can set this to class, attributes, etc..
For more details the AngularJs directives guide is really good:
http://docs.angularjs.org/guide/directive
Hope this helps.

Resources