In directive, we have set $scope.checkValue = true, and the same scope is passed to ngstrap modal dialog.
below is the code from directive link function which is called on button click and popup the dialog:
return {
templateUrl: "../Views/userSubscriptionView.html",
restrict: 'E',
scope: {},
link: function ($scope, element, attributes) {
$scope.checkValue = false; //this is bind to checkbox model but not updating on check/uncheck.
function DoOpenDialog()
{
//other code
var myOtherModal = $modal({ scope: $scope, templateUrl: "../Views/SubscribePopup.html", show: false , persist:false});
myOtherModal.$promise.then(myOtherModal.show);
}
Below is the code from dialog:
<input type="checkbox" ng-model="checkValue"/>
{{checkValue}}
The problem is: when I check the checkbox to true or false, model 'checkValue' is not updating. I need to change the state of other control based on the checkbox check state.
Thanks
I use to solve this by explicitly setting the ng-true-value and ng-false-value properties :
<input type="checkbox"
ng-true-value="'true'"
ng-false-value="'false'"
ng-model="checkValue"
/>
Notice the single quotes around 'true'. Ultimately everything is passed as strings, not as booleans or integers. I use the same approach when I have to deal with a boolean (tinyint) 0 / 1 value from mysql: ng-true-value="'1'" and so on.
Related
So I have my SPA application.
Here on plunker (I'll not paste all the code, as it is too much) you can see the it's parts recreation (the structure and the hierarchy are the same).
Where did the problem started...
By the design doc, On one of the pages we have a link to a policy documentation and a checkbox for a client to check, that he did read it.
By design:
Checkbox is always enabled, so client could always attempt to check it
After the client opens the policy documentation (click on the link), the checkbox should turn checked when client is clicking on it
If client didn't opened the (clicked) the policy documentation link yet and tries to check the checkbox, it return to be not checked at the moment he releases the mouse, and relevant error message should be shown
UPDATED:
Thanks to Rafaeelloo and Kobi Cohen I could get the code simplified a lot, and to get rid of the watches, and useless stuff...
For now this is what I have...
Here is the directive controller:
app.directive('checkBox', [function() {
var directive = {
scope: {},
restrict: 'E',
controller: function() {},
controllerAs: 'checkBoxCtrl',
bindToController: {
ngModel: '=',
callback: '&callback',
text: '#'
},
templateUrl: 'check-box.directive.view.html',
link: function() {},
require: 'ngModel'
};
return directive;
}]);
And directive html:
<div class="checkboxContainer">
<label class="btn btn-checkbox" ng-class="{'active': checkBoxCtrl.ngModel}"
ng-click="checkBoxCtrl.ngModel = !checkBoxCtrl.ngModel; checkBoxCtrl.callback()">
<span class="checkboxPic"></span>
<span class="checkboxText">{{checkBoxCtrl.text}}</span>
</label>
</div>
Here is view html:
<check-box text="check me" ng-model="viewCtrl.checkBoxResult"
callback="viewCtrl.callback()"></check-box>
<br/>
<a ng-click="viewCtrl.openGoogleClicked = true" href="//www.google.com" target="_blank">Open Google</a>
<hr>
<h3>Status</h3>
check box result: {{viewCtrl.checkBoxResult}}
<br/>
google opened: {{viewCtrl.openGoogleClicked}}
<br/>
callback function called: {{viewCtrl.callbackCalled}}
And this is view controller:
angular.module('app').controller('viewController', ['$scope', function($scope) {
this.checkBoxResult;
this.openGoogleClicked;
this.callbackCalled;
this.callback = function callback() {
this.callbackCalled = true;
if (this.checkBoxResult && angular.isUndefined(this.openGoogleClicked)) {
this.checkBoxResult = false;
}
};
}]);
The question/problem/opened question: Callback is called before the ngModel of the view controller had been changed. So it doesn't really meter if I change it back to false within the callback, or not, as after a callback the directive (as I understand) still binds the new value to it.
Is there a cure to this?
Depending on what you're trying to do, you may do it like here (here)
or you can write validator that has function to determine validity (here is example of writing your own validator) then your form and checkbox will have invalid what is in my opinion better than disallowing user to check the checkbox
I think I'm missing something with $validators and $setValidity (which I understand, do the exact same thing so you don't need both - please correct me if I'm wrong). Whether I have the $validators statement in there or not, I get the ng-invalid class added to the input form, which is adding a red border around the input. So why do I need the $validators? I am trying to set the parent form to be invalid if a user does not select a row from the dropdownnin the directive template. I don't want to show any error messages or anything, I just want to add the invalid class and red border based on if a row in the dropdown was selected.
Should I be using $validators or $setValidity? Do I need both $validator and $setValidity like I have below? Also, does $setValidity required ngModelCtrl or not? I get undefined for setValidity if it is not inside the $validators function. Any help is appreciated.
If I want to make the parent form invalid as a whole if no selection is made and I am getting ng-invalid class when I touch and then blur if no selection is made without $validators and $setValidity, then why do I need the $validators and $setValidity??
index.html
<form name="myForm">
<validator
rows="[{name:'tom', city:'san fran', state: 'mn', zip: 34212},
{name: 'joe', city:'san fran', state: 'mn', zip: 45675}]"
ng-required="true"
ng-model="hey">
</validator>
</form>
validate.js - DDO
return {
restrict: 'E',
require: {
ngModelCtrl: 'ngModel',
formCtrl: '?^form'
},
replace: true,
templateUrl: 'view.html',
scope: {},
controllerAs: 'ctrl',
bindToController: {
rows: '=',
onSelected: '&?', //passsed selected row outside component
typedText: '&?', //text typed into input passed outside so
//developer can create a custom filter,
//overriding the auto
textFiltered: '#?', //text return from the custom filter
ngRequired: "=?" //default false, when set to true the component
//needs to validate that something was selected on blur.
//The selection is not put into the input element all the
//time so it can't validate based on whether or not
//something is in the input element itself.
//I need to validate inside the controller where I can see
//if 'this.ngModel' (selectedRow - not passed through scope)
//is undefined or not.
},
controller: 'validatorController'
};
.
function validatorController () {
var ctrl = this;
var rowWasSelected = false;
var input = ctrl.formCtrl.inputField;
//called via ng-click on the dropdown row
//if this is called a row was selected
ctrl.rowSelected = function (row){
rowWasSelected = true;
}
//called via ng-blur of the input element
ctrl.ngModelCtrl.$validators.invalidInput = function (modelValue, viewValue) {
return rowWasSelected;
}
ctrl.$onInit = $onInit; //angular will execute this after
//all conrollers have been initialized, only safe to use
//bound values (through bindToController) in
//the $onInit function.
//i understand this need to be there with Angular 1.5
//using ngModel in the controller
//but I really only need to validate on ng-blur of the input
function $onInit() {
ctrl.validateInput();
}
}
};
}
view.html - template for directive
<div class="dropdown" ng-class="{'open' : ctrl.isOpen}">
<div class="form-group">
<input type="text" class="form-control" name="inputField"
placeholder="select" ng-click="ctrl.openDropdown()"
ng-blur="ctrl.validateInput()"
ng-model="ctrl.currentRow.name"
ng-required="ctrl.ngRequired">
</div>
<ul class="dropdown-menu list-group">
<li class="list-group-item" ng-repeat="row in ctrl.rows"
ng-click="ctrl.onSelectedLocal(row)">
{{row.name}}
</li>
</ul>
</div>
I must be getting the invalid class regardless of the $validators function I have because it is adding the ng-invalid class whether its there or not??
$setValidity(validationErrorKey, isValid);
Change the validity state, and notify the form.
This method can be called within $parsers/$formatters or a custom validation implementation. However, in most cases it should be sufficient to use the ngModel.$validators and ngModel.$asyncValidators collections which will call $setValidity automatically.1
I have a button with this attribute: ng-disabled="ProductionBtnDisabled".
When angular renders the html the value of ProductionBtnDisabled is undefined and after initiating the controller ProductionBtnDisabled has the correct value.
So, at first the ng-disabled is not disabled because undefined=false in javascript/angular. This is a problem for me. I want the default value to be true.
Is any one has any suggestion to handle this?
What about using ng-cloak? It didn't work for me. I don't mind hiding the buttons until the scope is rendered.
Thanks!
I think there is no default settings for ngDisabled. If you needs a global solution, you can try directive.
.directive('specialDisabled',function() {
return {
restrict: 'A',
scope:{specialDisabled: '='},
link: function(scope, element, attrs) {
scope.$watch(function(){return scope.specialDisabled}, function(){
// set disabled attribute here
element[0].disabled = !scope.specialDisabled;
});
}
}
});
Then, you can called specialDisabled directive anywhere.
<input type="checkbox" ng-model="chk">
<button special-disabled="chk">My Button</button>
http://plnkr.co/edit/BA2ntTrzmItwvEj8UKOc?p=preview
I want my input to be required based on condition.
<input type="text" custom-directive ng-required="isRequired" />
I have defined property isRequired as boolean false. Required functionality works fine according to the isRequired property. But inside the custom directive i am getting $attrs.required as true for all scenarios.
module.directive('customDirective', function () {
var link = function ($scope, $el, $attrs, $controllers) {
$scope.required = $attrs.required;
}
return {
restrict: 'A',
link: link
};
});
Thanks
I am unable to explain why $scope.required would be true in this case (perhaps you are setting it to true somewhere else and should be using a child or isolation scope?)... I would expect it to be undefined based on what you have provided. The other possibility is that you have multiple elements with this directive in the same scope and one of them is setting that value to true for all of them.
By replacing your $scope.required = $attrs.required; line with
$attrs.$observe('required', function(value) {
$scope.required = value;
});
it should properly pick up the value of the required attribute (and when it changes!).
If you have that directive being applied to multiple elements in the same scope you should use a child scope. All you need to do is add scope: true to the object returned by your directive.
If this does not work, please post more of your application's code.
I was able to see true or false and return strings in checkboxes with ng-true-value and ng-false-value, but in additional, I want to give the checkbox an integer and if it's checked, it returns an integer.
Which should be similar to when I get a value from a selectbox: http://jsfiddle.net/PuDRm/
But I can't seem to get the same idea in a checkbox: http://jsfiddle.net/PuDRm/1/
<input type="checkbox" ng-model="testc" ng-true-value="Yes" ng-false-value="No" ng-change="processtest()" /> Yes
I'm a total newbie and trying to understand AngularJS.
It sounds like you are trying to bind to two separate values with the checkbox.
In the select the view is the name you gave e.g. 'test1', and the model is the number, e.g. '1'. For the checkbox, the view is a check or a blank square and the model is Yes/No (or whatever you want to put in the ng-true-value and ng-false-value). There's no room to have it produce a number too.
It would be simpler to let the checkbox model be the default (boolean) type by omitting the ng-true-value and ng-false-value attributes. You can then display the number and text based on this like in this updated fiddle: http://jsfiddle.net/D5DGf/1/
The {{ ... }} bindings take care of updating when the function values change, so you don't need to use ng-change either.
What was wrong with the original checkbox fiddle?
In the processtest function you are taking the model (Yes/No) and changing it to always be either 8 or 1. The checkbox (in fact, ngModel) doesn't understand this as it expects to always see Yes/No. As it doesn't know what to do, it falls back to being unchecked.
This is why the checkbox in the original fiddle is uncheckable.
If you still want to set use a number for your model and checbox value, you could do it with a custom directive to parse the string back to integer.
Demo: http://jsfiddle.net/qw5zS/
html
<input type="checkbox" ng-model="test" parse-int ng-true-value="1" ng-false-value="0" />
js
app.directive('parseInt', [function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, controller) {
controller.$formatters.push(function (modelValue) {
console.log('model', modelValue, typeof modelValue);
return '' + modelValue;
});
controller.$parsers.push(function (viewValue) {
console.log('view', viewValue, typeof viewValue);
return parseInt(viewValue,10);
});
}
}
} ])
But this might not be a good practice using checkbox, you should stay with the default behavior and use a boolean, then format the view like you want, but keep your data clean.
If you change the column in database from integer to char, it works with
<input type="checkbox" ng-model="testc" ng-true-value="1" ng-false-value="0" ng-change="processtest()" /> Yes
Here is the solution which worked best in my trials :
<input type="checkbox"
ng-true-value="{{ 1 | json }}" ng-false-value="{{ 0 | json }}"
ng-model="myVariable">
Another approach without the needs of ng-model, ng-true-value and ng-false-value. Let's keep those the way they are.
js
angular.module('whateverModule')
.directive('toggleInt', function () {
function link ($scope, $element, attr) {
$element.on('click', function () {
$scope.$apply(function() {
$scope.toggleModel = +!$scope.toggleModel;
});
});
$scope.$watch('toggleModel', function (value) {
$element.prop('checked', !!value);
});
}
return {
restrict: 'A',
scope: {
toggleModel: '='
},
link: link
};
});
html
<input type="checkbox" toggle-int toggle-model="intModel">
<span>Value: {{intModel}}</span>
What I ended up doing was just using an if statement on the controller.
Example:
$scope.status = ($scope.status === 1 ? true : false);