AngularJS required radio buttons needs two click events to be valid - angularjs

I have a very simple form where a radio button is required to be selected in order for a form to be valid. The radio buttons are generated by ngRepeat.
As you can see from this fiddle, while the desired behavior is that when the radio button is clicked for the first time, that should validate the form (being the only element), however notice that it takes an additional click (on the same radio button or any other) to validate the form:
http://jsfiddle.net/Xsk5X/3/
What am I missing?

All the other solutions are work-arounds: All you have to do is remove the name attribute, when you use the ng-model attribute you don't need it and they conflict.
Specifying the name causes Angular to get confused because it changes the value once for the angular model and another time for the form element name.

I had this problem because a colleague had copied the radio buttons in the same page and hidden them for temporary reference, so duplicate radio inputs with the same name

Try adding the ng-click attribute to your radio button input.
Credit to Manny D for noting this first. Yes, this is a little hackish, but it works. E.g.,
<input type="radio"
name="groupName"
ng-model="editObject.Property"
ng-value="someValue"
ng-click />

The reason why this is breaking - is because you're setting all radio boxes to be required. As a result, depending on how you write it - angularjs is saying it's invalid because not all have been selected at some point.
The way around this is to do something like the following:
Using checkboxes and required with AngularJS
(check the 1st and 2nd answers). This will resolve your problem.

Seems like an AngularJS 1.0.3 $scope.$apply update problem.
Tested your exact Fiddle in 1.0.2 (check it out yourself) and it works the way you expect it too.
It doesn't seem like there's anything wrong with your code, just that $scope.$apply(or $digest) isn't working as expected on the first select.
A very simple fix is to force the $scope to also update on every select, try changing the following line of code in your form:
<p>Favorite Beatle</p>
change it too:
<p>Favorite Beatle: {{name}}</p>
And you will see how myForm.$invalid is updated even after the first click.
I would try it out with the latest AngularJs version and let us know if that happens there too.
Another solution I can think of it setting the default selected radio, which will cause myForm.$invalid to be false from the beginning. you can do this by adding the following line in your controller code:
$scope.name = "John";
or any default name you want.

Some times the $digest cycle dosen't $apply(fn) because you have two o more instances.
For fix this you need $apply this trick manually, so put this in your directives:
angular.('myApp',[])
.directive('ngRadioExtend', ['$rootScope', function($rootScope){
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, iElm, iAttrs, controller) {
iElm.bind('click', function(){
$rootScope.$$phase || $rootScope.$apply()
});
}
};
}])
and use it as:
<input type="radio" name="input_name" ng-model="some" value="F" ng-required="true" ng-radio-extend>
<input type="radio" name="input_name" ng-model="some" value="M" ng-required="true" ng-radio-extend>
DONE it's the correct way!

The problem of the scope not getting updated still occurs in 1.1.5
A simple work around is to just add
<span ng-show="false"> {{name}} </span>
Fiddle: http://jsfiddle.net/jonyschak/xaQJH/

For IONIC v1,
add name="" to prevent ionic auto-generate attribute name.
Then, I can change the selected item with only one click.
<ion-radio class="label-ticket"
ng-repeat="topic in vm.listTopic track by $index"
ng-value="topic"
ng-model="vm.topicSupport"
name="">
{{ topic.title }}
</ion-radio>

Related

Checkboxes in text angular not saving

I'm using text-angular to save html-based content into database and i want to save checkboxes with the checked attribute on them. I've tried to use the input field like below but text-angular doesnt render checkboxes with checked attribute. Is there any way to do this without doing pure css checkboxes?
<input type="checkbox" checked>
EDIT: The code I am using:
<text-angular data-ng-model="example_content" placeholder="Content..."
rows="5">
And inside the textarea of the text-angular directive, I am trying to insert the input from above but it renders without checked attribute
I looked up in text-angular's sanitizer library textAngular-sanitize.js to find out that the checked attribute isn't part of their htmlAttrs attribute map.
Hence, the only option we're left with is to override the sanitizer JS file with the edit. Moreover, you can add other attributes/tags if you want (Do consider vulnerabilities though!)
Here's the working example plunker forked from official text-Angular plunker. Notice the ta-sanitize.js included in plunker which is modified version of their textAngular-sanitize.js
Hope this helps!
You can achieve by using ng-click
<input type='checkbox' ng-click='onsaveValue()' ng-model="saveValue">

ng-model not working with typeahead

I am using angular's typeahead, and running into trouble with ngModel.
Here is my typeahead html
<input
type= "text"
ng-model= "symbol"
placeholder= "begin typing"
typeahead= "hit.message for hit in getTypeAheadContents($viewValue)"
typeahead-loading= "loadingSymbols"
typeahead-editable= "false"
typeahead-on-select= "onSelect($item, $model, $label)"
typeahead-min-length= 2
typeahead-wait-ms= 500
class= "form-control"
/>
<input ng-click= "search()" value= "Search!"/>
Here is the code in my controller (quite basic for the time being)
$scope.search = function(){
alert($scope.symbol);
}
Now, the autocomplete code works as expected, but when I click the search button, I get the alert message "undefined"
What's even weirder is that I tried setting
$scope.symbol = "";
at the beginning of my controller, and when I click the search button without typing anything into my typeahead, I get the empty string alerted back to me, as expected. However, when I DO type something into the typeahead and again hit search, I get back "undefined" once again. So clearly, angular's typeahead is not playing very nicely with ng-model, but I'm not sure what to do here.
Advice?
Just set typeahead-editable="true" :-)
Don't know if this is still an issue for you. But I've tried the latest release of angularStrap (2.1.4) and with that I got it working when I set the ng-model to an object on which I set a property.
$scope.selectedPart = {}
<input type="text"
class="form-control"
ng-model="selectedPart.part_id"
data-animation="am-flip-x"
ng-options="part.value as part.name for part in parts"
placeholder="Selecteer onderdeel"
bs-typeahead>
Somewhere in some function (could be a deep $watch)
console.log($scope.selectedPart.part_id)
This doesn't really answer the question, but I sort of got around this issue by setting a different scope variable equal to the user's input inside the getTypeAheadContents function, and then using that variable (instead of 'symbol') inside the search function.

Binding valid checkbox to enable button angularjs 1.2.x

I'm trying to use Angularjs's built in form validation, but when I add a required field to a checkbox to make sure its checked I get odd results. If I do the opposite of the value I'd like it seems to work fine. The following fiddle will explain it more thoroughly.
This fiddle works great when you're using Angularjs 1.0.4, but if you switch Angular to 1.2.1 it breaks all over the place. Is there a new way of doing this now? or would this be considered a bug?
EDIT
I simplified the code to make it make more sense, check out this fiddle. The key problem here is that it's doing the opposite of what I would like it to do, but if I switch it the entire thing falls apart. I've also replaced the older code I had here with the newer fiddle. You can still see the older fiddle code in the above link.
Here is the html:
<div ng-controller="myCtrl">
<ng-form name="myForm">
<input type="checkbox" ng-model="value.checkbox" name="group-one" ng-true-value="1" ng-false-value="0" ng-required="value.checkbox==1" />
<input type="submit" value="Send" ng-disabled="myForm.$invalid" />
{{choice}}
</ng-form>
</div>
Here is the controller:
function myCtrl($scope) {
$scope.value = {"checkbox":""};
}
This appears the be a bug, though I'm not sure it's the same as your original problem. The required directive is not functioning properly when an ng-true-value is specified.
Found an existing bug report.
If you use ng-click, you should pass $event in and then get the choice from $event. Or you can use ng-checked to get the value directly.
ng-click="updateQuestionValue($event)"
$scope.updateQuestionValue = function($event){
var choice = $event.target;
//...
}

ngRepeat breaks the Foundation Switch CSS. How can I fix it?

I'm trying to use the Switch component from Zurb's Foundation.
It works great until you put it inside an ng-repeat. Then, all the switches except the last one are broken--they don't display the labels until you click them.
Here's a JSBin documenting the issue. Anyone know what's up?
You need ng-model on your radios. It works fine in your JSBin if you include an ng-model on each radio button.
According to the docs, value is also required.
Edit:
Okay look at this version, I finally got it to work with both ng-model and ng-value, which I've learned is preferable to value. What do you think, does that work for you?
Apparently ng-repeat created a child scope for each iteration. Using $parent seems to be a way around that.
Found I had to use "ng-checked" in the following fashion for it to work as expected within an "ng-repeat". As long as the ng-clicked var is unique per switch, should work as expected. Make the toggle function something that toggles the visible value between true and false.
<div class="switch" ng-click="toggle()">
<input type="radio" ng-checked="!visible">
<label>Off</label>
<input type="radio" ng-checked="visible">
<label>On</label>
<span></span>
</div>
Hope that helps someone.

Using {{$index}} in compiled directive within ng-repeat (jQuery UI buttonset)

In an ng-repeat list, I'm having a terrible time putting an ON/OFF button (using JQ UI wrapping radio buttons) for each item in the list.
When using radio buttons, it seems JQ UI buttonset needs both the "input" and "label" tags plus also the 'for' of the label must match the 'id' of the input.
I can use {{$index}} to make them unique, like this:
<label for='algoOn{{$index}}'>ON</label>
<input type='radio' [... blah blah ..] id='algoOn{{$index}}'>
The problem is calling $().buttonset() once the DOM is ready. I've tried various things (dom.ready, link function etc), but had to resort to calling it after a delay [ $('.buttonme').buttonset() ] to trigger all buttons on the page. Hacky.
However, I'd like to wrap the on/off button in a directive. Still have the same problems with needing unique IDs. (If you don't have unique IDs the buttons get bigger and bigger on each successful call in the directive's link function)
BUT... using {{$index}} in the template gives me a mysterious syntax error:
Syntax error, unrecognized expression: [for=on{{$index}}] <onoffbtn prop="win.runstate" class="ng-isolate-scope ng-scope">
(even though code doesn't have 'for=on{{$index}}' in it!)
The directive is the preferred approach but can't figure out how to get around this one.
Secondly, in the directive, all radio buttons are in sync after the first click, but when the page first loads the buttons in the directive are both blank. It doesn't set itself to the model right away. I thought to do that in the link function (eg. element -> find the input -> set the value) but angular has re-written all of the 'names' and 'ids'.
Plunker showing both issues is here: http://plnkr.co/edit/DTy8dGsRDVVDnWZBYlqQ
Thanks!
Like you said this is doable from a directive. Using your html, I just added buttonset to the wrapping div:
<div id='A{{$index}}' buttonset>
<label for='algoOn{{$index}}'>ON</label>
<input class="buttonme" type='radio' name='onoff{{$index}}' ng-model='win.runstate' ng-name='onoff' value='running' id='algoOn{{$index}}'>
<label for='algoOff{{$index}}'>OFF</label>
<input class="buttonme" type='radio' name='onoff{{$index}}' ng-model='win.runstate' ng-name='onoff' value='stopped' id='algoOff{{$index}}'>
</div>
Here is how the buttonset directive looks
angular.module('button', [])
.directive('buttonset', function() {
return function(scope, elm, attrs) {
$(function(){
$(elm).buttonset();
});
};
});
Here is the plunker, no more hacks :)
Update:
The errors you are getting have to do with the fact that the dwbuttonset directive is executing before the code is compiled by angular. Therefore, what you need to do is to wait until this has been done. You can use $timeout with a 0 value (see this question) in order to queue your method until everything has been loaded.
Example:
.directive('dwbuttonset', function($timeout){
return function(scope, elm, attrs) {
$timeout(function(){
$(elm).buttonset();
});
}})

Resources