I am working with the bootstrap-multiselect control. I need to execute multiselect() on a select element once all of the options have been populated by Angular.
Here is the select box, bound to a $scope property, with the options generated from an array of accountInfo objects snippet from my view:
<select id="property" multiple="multiple"
ng-model="selectedProperty"
ng-options="account.property_name group by account.client_name for account in accountInfo">
</select>
So once the options exist, I need to call $("#property").multiselect() to generate the bootstrap control, but I am looking for an event to listen for that tells me when all the options have been generated.
Instead of initializing bootstrap-multiselect control in a controller, do it in a directive link() function which is called after the corresponding element is rendered.
app.directive('multiselect', function() {
return {
restrict: 'A',
link: function(scope, element) {
element.multiselect();
}
};
});
Here's a demo.
Related
Hi I have created a table using scrollable-table and now I need to add a checkbox in the table for every row. How to change the value of the checkbox to checked/unchecked based on the value of the model. i.e if the value of the model is true which I am getting from mysql table then the checkbox should be checked for the particular row. The other values which are false should remain false.
//== You can define a directive to bind click function, html: <tr toggle-model="yourScopeModel"></tr>
angular.module('CommonDirective', []).directive('toggleModel', function() {
return {
restrict: 'A',
scope:{
toggleModel: '&'
},
link: function(scope, element, attrs) {
angular.element(element).click(function(){
scope.toggleModel = !scope.toggleModel;
});
}
};
});
//==This is just an example code (not test yet). Hope to help you!
The mistake I made was when comparing for checked value ng-model was in string and for checkbox it is boolean value. So I should have given that inside quotes while checking. This is the syntax now I have used.
<input type="checkbox" id="'#toggleeventtoggleApp_' + $Index" ng-true-value="'true'" ng-false-value="'false'" ng-model="x.userinput" ng-change="AutoStartToggle($index,x);"><br>
In Angular, I am trying to validate a value of a field on blur. I have a list of customers, and I want to check if the model value in the field is in my list of customers. If not, I want to set the validity to false.
I know that ng-model-options="{updateOn: 'blur'} exists, however, I can't use this because the field is a typeahead so it must update based on the model. The validation is what needs to happen on blur.
The answer seems to be:
Write it as a function in the controller and use $setValidity just as you would in a directive. Use ng-blur to trigger the function in the input field.
-However, I keep running into examples where a custom validation (make the field invalid if the model value does not match one in the list) is only written as a directive. Are there examples of custom validation written as a function?
Write a directive that only triggers on blur.
However, I can't find examples that do either of these things.
Does anybody have an example of custom validation as a function OR a directive that only updates on blur of the field?
I found this link very helpful for custom validation but I still have the same problem with the difference between a function and a directive: How to add custom validation to an AngularJS form?
** My typeahead works, I do not need help getting uib-typeahead working but rather the accompanying custom validation
Here the example of custom validation triggered on blur:
angular.module('myApp', [])
.directive('customValidation', function() {
return {
require: 'ngModel',
link: function(scope, el, attrs, ngModel) {
el.bind('blur', function(event) {
scope.$apply(function() {
ngModel.$setValidity('customValidation', scope.name == 'test');
});
})
}
};
});
Plunk
I'm trying to make a directive which should remove the first option of a select.
I'm using this html to generate the select box:
<select remove-whitespace ng-model="user.encryption">
<option ng-repeat="r in selectButtons" title="{{r.text}}" ng-selected="$first" value="{{r.value}}">{{r.text}}</option>
</select>
This part of code is in my controller to populate the select box in the view:
$scope.selectButtons = [
{text: "Clear-Text", value: "no_encryption"},
{text: "MD5", value: "md5_encryption"},
{text: "SHA1", value: "sha1_encryption"},
];
I'm using this as my directive:
.directive("removeWhitespace", function () {
return{
require: 'ngModel',
link: function (scope, element, attributes, ngModel) {
console.log(element.context);
}
}
});
When i do a console.log(element.context); the following context appears in my browser console:
Yet I can't seem to remove the option with value "? undefined:undefined ?"
It seems i've found a solution to my own question:
To properly populate a select box you need to use ng-options instead of ng-repeat.
I ended up using the following:
<select ng-model="selectButton"
ng-options="r.text for r in selectButtons">
</select>
This will populate a selectbox without whitespace. And the directive is not needed anymore.
The first element (? udefined:undefined ?)is there because the current value of the ng-model does not match any of the options. It will go away on its own if you do something like this in your controller:
$scope.user.encryption="no_encryption"
To answer the question fully, here is a simple directive that removes the first option of a select, though I would advise against using anything like it because it would be better to use ng-options possibly combined with a filter
angular.module('app').directive('removeFirst',function(){
return{
link:function(scope,element) {
element.find('option')[0].remove();
},
}
})
I am having a bit of a problem (mostly because of my lack of knowledge of AngularJS directives). I am using the Rating Directive directive from the UI Bootstrap library combined with my own custom validation. Multiple rating directive instances are created using ng-repeat from an object array from my controller. I use other scope variables to set the default "Rate Me" text, the custom CSS classes 'ratingOptions.ratingStates' and the max value limitiations 'ratingOptions.max'. All is working as desired... This is my directive code in the view (please note that the container form is called "categoryRatingFrom":
<div data-ng-repeat="cats in categories">
<div data-ng-form name="RatingFrom">
<div class="row no-bottom-padding">
<label class="col-sm-4 control-label">#{{ cats.name }}</label>
<div class="col-sm-8">
<div class="no-outline"
data-rating
data-ng-model="cats.value"
data-max="ratingOptions.max"
data-rating-states="ratingOptions.ratingStates"
data-on-hover="cats.onHover(value)"
data-on-leave="cats.onLeave()"
data-rating-validate > <!-- Notice the custom directive -->
</div>
#{{ cats.hoverState || cats.items[cats.value - 1].name || rateMe }}
</div>
</div>
</div>
</div>
Now I wish to set the directive instance to invalid should a value not being set, the default value is zero but the user must enter a value from 1 to ratingOptions.max (which is currently 6). I have a custom directive to validate this called ratingValidate. This is being invoked/bootstrapped and I am able to determine the current value of each directive instance, however I wish to initially set the directive/form-item to invalid and once the user selects a value we set the directive /form-item/instance to valid. This should be fairly easy but with using an ng-repeat I am unsure how to reference the specific form item. If anyone could help explain what I need to do whilst I experiment and search the AngularJS docs I would be most appreciative. This is my directive...
angular.module('myApp')
.directive('ratingValidate', function () {
// ratingValidate
return {
restrict: 'A', // only activate on element attribute
require: '?ngModel', // get a hold of NgModelController
link: function (scope, element, attrs, ngModel) {
// do nothing if no ng-model
if (!ngModel) {
return;
}
// Listen for change events to enable binding
element.bind('click change', function () {
console.log(element[0], attrs);
if(attrs.ariaValuenow === 0){
ngModel.$setValidity('', false); // What goes here??? How do I reference the item?
} else {
ngModel.$setValidity('', false); // What goes here??? How do I reference the item?
}
});
}
};
})
;
How Angular Validation Works
Angular uses the 'name' attribute to create the $scope variables used for validation.
For example, if you have an input field with a 'required' attribute:
<form name="myform">
<input name="firstname" ng-model="firstname" type="text" required/>
</form>
Then to access the validation properties on $scope, you would do:
var validationFailed = $scope.myform.firstname.$error.required;
Where $error is an object that has 'required' as a Boolean property.
In the 'required' directive, you would see something like this:
if(attrs.value == ''){
ngModel.$setValidity('required', true); // failed validation
} else {
ngModel.$setValidity('required', false); // passed validation
}
You can pass any string to $setValidity, and it will set the $error property for you. For example, if you did:
$setValidity('test', true)
Then there would be an $error property named 'test' and it would be set to true. You can then access the property like this:
$scope.myform.firstname.$error.test
Other validation properties that are available are:
$scope.myform.firstname.$valid
$scope.myform.firstname.$invalid
$scope.myform.firstname.$pristine
$scope.myform.$valid
$scope.myform.$invalid
$scope.myform.$pristine
Hope this helps to answer your question.
To overcome this I added the following to the directive HTML:
name="rating#{{$index}}
and in the directive
ngModel.$setValidity(attrs.name, true); // or false depending on the condition
I am creating a new directive for the select element. As a best practice, I would like to receive some of the options from the server and one option I want to create in the client code e.g. "Search all cars".
This is an example of how I want it to look:
<select>
<option value="">Search all cars</option>
<option value="aud">Audi</option>
<option value="bmw">BMW</option>
<option value="maz">Mazda</option>
</select>
It is important that the value of "Search all cars" is empty.
But even though I have added an empty element in the select (ref other SO posts) it still gives me an unwanted option:
<option value="?" selected="selected"></option>
Here is an plunker example of the issue/bug using an Angular directive with transclude and replace.
Anyone got a suggestion of how to solve this?
I have also added an issue to the angular team here.
EDIT:
The reason why I would like to have this as an directive is that I want to decide if I should have the "Search all cars" option or not depending on where it is implemented in my application.
EDIT2:
Angular team confirms that this is a bug. "It looks like the root reason is that if an unknown option is added after the initial setup, then it will not replace the generated unknown option" - lgalfaso.
#Yoshi is right, it's to do with ngTransclude. As soon as you move the default option into the directive itself, the problem goes away. To work around this issue, since you don't care about the default value so much, you can modify the directive slightly and just import the text for the default option:
app.directive('mySelect', [function () {
return {
restrict: 'E',
replace: true,
scope: {
default: '#'
},
template: '<select ng-options="key as value for (key, value) in myMap"><option value="">{{ default }}</option></select>',
link: function postLink(scope, element) {
scope.myMap = {"bmw":"BMW","maz":"Mazda","aud":"Audi"}; // e.g. hashmap from server
}
};
And then your HTML becomes:
<my-select ng-model="myModel" ng-change="doSomething(myModel)" default="Search all cars">
</my-select>
I just had the same issue as you and unfortunately #morloch's answer did not help me.
In my case, the transclusion is dynamic.
I started with your plunker and figured out that, if we use the transclusion during the prelink, it solves the issue.
link: {
pre:function preLink(scope, element, attrs, controllers, transcludeFn) {
scope.myMap = {"bmw":"BMW","maz":"Mazda","aud":"Audi"}; // e.g. hashmap from server
transcludeFn(scope, function(clone) {
element.append(clone);
});
}
}
Here is my plunker : http://plnkr.co/edit/4V8r6iW2aKCLLbpIZc5e?p=preview