Introduction
I' m writing checkbox tree directive using angular. Part of the behaviour is when I check checkbox in the middle of the tree, I need to unset all ancestor checkboxes and set all descendant checkboxes (see screenshot, transparent checkboxes are unchecked in fact).
https://www.dropbox.com/s/yx1bzqsamunmjpx/Screenshot%20from%202014-08-25%2018%3A39%3A44.png?dl=0
I'm using:
itemScope.$watch('checked', function setCheckboxes(newValue, oldValue) { ... });
For descendants everything works fine. I forEach child checkboxes and set them a new value, which in turn fires events for their descendants and so forth.
Problem is with ancestors. If I set parent checked value to false, it triggers event which sets all children to false which is not desired.
Question starts here:
I need to find a way to update (ancestor checkbox) model without firing event I subscribed with $watch. I know one way to wrap new value assignment in setTimeout(fn, 1), but I think it's not cool. What's the correct way of doing this?
Thanks!
You could use the ngChange directive on the checkbox to kick off the correct behavior, rather than $scope.watch. From the docs:
The ngChange expression is only evaluated when a change in the input value causes a new value to be committed to the model.
It will not be evaluated:
if the value returned from the $parsers transformation pipeline has not changed
if the input has continued to be invalid since the model will stay null
if the model is changed programmatically and not by a change to the input value
Related
I have some requirment which happen after the selecting from dropdown in combobox. But In some cases I getting default value. So for that which even i have to fier.
onchange and onselect is working when I select from the dropdown. But in my case I need event when Combo value is by default select.
So the change events don't fire when field's are created with a value so you will either have to run your post-change code after the init code (i.e. initComponent, constructor or render) or you could override the initValue method of the component and prevent it suspending those events on the initial value set.
Whether that's a good idea I'll leave up to you to decide!
Check out this Fiddle and the source file for the original code
I have a gist demonstrating my problem here:
https://gist.run/?id=e2ccd5925e383f2fc36ad277c31bcf23
The checkbox version works fine, if you remove a check, it updates the model right, but if you change the selected radio button, it will keep the true value on the radio that got it's selection removed. If I remove the model.bind="true" value, it will write "on" instead of true. I do want true/false, and not on/off.
I want the object to get it's property updated to be a true or false depending on if it's chosen or not, dynamically. In my scenario I don't know how many radio buttons or checkboxes will need to be selected. I only know that in the cases of it not being a collection, I only want one, and in the case that it is a collection, I want an unknown number selected.
Like the other answer mentions - <input type="checkbox"> behavior is different from <input type="radio">.
I have forked your gist and made the following changes to make your scenario with the radio button work in aurelia:
1) Added a function to the first object in your params collection called selectedChanged(it doesn't have to be there, could be on the viewmodel class instead, perhaps a better place for it). It is responsible for handling selection change in the radio button group, specifically it will iterate over a collection of options (second parameter), and set selected property to true on the option who's id matches the first parameter of the function, and to false on all other options.
2) There is an event on the input called change, I delegate it to a function called selectedChanged mentioned above, passing the option.id value and options as parameters.
https://gist.run/?id=5f38414fde799dfc145fc1291d9f2fd3&sha=f12283b08bfb45e77b8280d46a3709b6ccb82768
I think what you want to achieve (turning individual value on/off) is not achievable with radio, as the way it works (select a single value out of a set) is different with check-box (turning individual value on/off) (MDN reference). So If you truly want to have radio like appearance, with check-box behavior, consider employing some CSS and extra DOM elements to make it look like so, and behave like so.
I am facing one problem with textbox in angularjs.
When I am updating textfield data by some way(Like clicking button) then ng-change is not working. Please check plnkr
[https://plnkr.co/edit/32eE0ejSNBTkWJ4LVErR?p=preview][1]
When I am updating first name on button click ng-change is not firing, but when i am changing first name in textfield ng-change is getting fired
This behaviour is intended. It says this in the official documentation:
The ngChange expression is only evaluated when a change in the input
value causes a new value to be committed to the model.
It will not be evaluated:
if the value returned from the $parsers transformation pipeline has
not changed
if the input has continued to be invalid since the model will stay null
if the model is changed programmatically and not by a change to the input value
source
In your case, the last item in that list applies.
if the model is changed programmatically and not by a change to the input value
You'll have to use a watch in this case.
So I'm trying to build a custom autocomplete dropdown for a text input. To do it, I am listening for the keydown event and if it's an up or down arrow press, I'm setting a $scope.arrowSelectedItem variable to the proper one in the list. (As a side note, all the functionality works as far as selecting an item from the list that pops up. All I'm trying to do is highlight the current one that they've marked with the up/down arrows).
On the markup side, the items in the autocomplete list are output with ng-repeat, with ng-repeat="item in itemList". The ng-class expression I'm using is ng-class="{highlighted: item === arrowSelectedItem}". I know that the $scope.arrowSelectedItem is being updated on each arrow press by using console.log, but for some reason the class isn't being updated to the list item properly.
What I've found is that after the first time of hitting an arrow key, if I make the text input box lose focus, then the class is added. Then if I click back in the box, move the arrow to select a different item, click out of the input box, then click back in, the class is added to the new one. I know that sounds weird, but that's what I've found.
What I'm not sure about is why the ng-class expression isn't being evaluated on every arrow key press. Does anyone have any ideas why?
The answer here is that "raw" DOM events which fire outside of one of angular's built in directives (such as click events via ng-click etc) will not trigger a $digest cycle update. Until this happens the $scope properties will not be updated.
If you are in a position where you are listening for DOM events by using another framework, or simply using addEventListener(), you will need to let angular know about any changes by using $scope.$apply(), or by wrapping the code in a $timeout().
If you do this in your event handler, angular will trigger a new $digest cycle update for every keypress and your new scope values will propagate to the view.
I'm new to angular and I'm confused about needing to use $scope.$watch in the this very simple plunk in order to see my selection change. If the $watch is removed, the alert is not triggered. Should selection not be automatically bound when I select something and then the change event should trigger a digest and automatic watch?
You don't need $scope.$watch. You can simpy use ngChanged directive.
From Docs (emphasis mine)
Evaluate the given expression when the user changes the input. The expression is evaluated immediately, unlike the JavaScript onchange event which only triggers at the end of a change (usually, when the user leaves the form element or presses the return key). The expression is not evaluated when the value change is coming from the model.
DEMO