How to prevent property change on Angular JS

I'm using AngularJs on my project and i've a property on my viewModel that is connected to a dropdown (< select >)

that dropdown have a empty value witch is selected by default, what i want is to prevent user to select that empty value after he select some other value.

ive started to look to $watch, but i dont know if there is some way to cancel the "changing oof that property", some thing like this:

$scope.$watch('myProp', function (newVal, oldVal, scope) {
    if (newVal) { scope.preventDefault(); }
}

any idea, this is the base idea, on a more advanced development i need to ask users for a confirmation.

any ideas?

Answers:

Answer

what i want is to prevent user to select that empty value after he select some other value

This should happen automatically for you, as long as you don't assign the ng-model property a value initially. So using the <select> shown below, don't initialize $scope.selected_year in your controller:

<select ng-model="selected_year" ng-options="year for year in years"></select>

When the list displays initially, Angular will have added an option like this to the HTML, since $scope.selected_year is not currently set to a valid option/value:

<option value="?" selected="selected"></option>

After selecting a valid choice, that option will magically disappear, so the user will not be able to select it again. Try it in this fiddle.

If the ng-model property already has a valid value assigned when the select list is first displayed, then you can assign a controller function to the undocumented ng-change parameter:

<select ... ng-change="preventUserFromDoingXzy()">

Inside function preventUserFromDoingXzy() you can do what you need to do to control what the user can select, or modify the model.

Answer

You can just add ng-required to the select. If there is no initial value to the model then an empty option will be added and on change to a valid value it will remove the empty option

EDITED jsFiddle to revert to previous value and to include the ng-change directive.

From the docs:

The expression is not evaluated when the value change is coming from the model.

This is useful in not interfering with change listeners and creating an infinite loop when reverting the old value in the $apply function

Controller

$scope.options = [{value: 'abc'},{value: 'def'}];

var confirmDialog = function(newVal, yes, no) {
    // obviously not a good way to ask for the user to confirm
    // replace this with a non blocking dialog

    //the timeout is only for the confirm since it's blocking the angular $digest
    setTimeout(function() {
        c = confirm('Is it ok? [' + newVal.value + ']');
        if(c) {
            yes();
        }
        else {
            no();
         }
    }, 0);
};

//Asking for confirmation example
function Ctrl($scope) {
    $scope.options = [{value: 'abc'},{value: 'def'}];

    $scope.select = undefined;
    var oldSelect = undefined;
    $scope.confirmChange = function(select) {
        if(oldSelect) {
            confirmDialog(select,
                 function() {
                    oldSelect = select;
                 },
                 function() {
                    $scope.$apply(function() {$scope.select = oldSelect;});
                });
        }
        else {
            oldSelect = select;
        }
    }
}

Template

<div ng-controller="Ctrl">
  <select ng-model="select" ng-options="o.value for o in options"
          ng-required ng-change="confirmChange(select)">
  </select>
</div>
Answer

Probably the easiest, cleanest thing to do would be adding an initial option and setting disabled on it:

<option value="?" selected="selected" disabled></option>
Answer

Actually, it is easier to remove the empty value. Suppose you have a list of options:

$scope.options = [{value: ''}, {value: 'abc'},{value: 'def'}];

and a select:

<select ng-model="select" ng-options="o.value for o in options"></select>

Then $watch the model:

$scope.$watch('select', function(value) {
    if (value && value !== '') {
        if ($scope.options[0].value === '') {
            $scope.options = $scope.options.slice(1);
        }
    }
}, true);

See it in action here.

PS Don't forget the objectEquality parameter in the $watch or it won't work!

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.