AngularJS getter / setter

15,950

user1 tries to direcly use the getter/setter provided by the name1 objet, it doesn't work properly, can you explain why?

The issue is with the context, You are just merely copying the function reference name1.name by doing:-

    $scope.user1 = {
      name: name1.name
    };

so when it is run this in the getter will actually point to the window/global (in non strict mode). You can workaround this by using Function.bind.

Example:-

    $scope.user1 = {
      name: name1.name.bind(name1)
    };

Demo

Is there a way to avoid to rewrite a "proxy" for each getter/setter as I've done in user3?

I would just create a wrapper so that i don't run into context issues like these.

    $scope.user = getModel('name', 'Brian');

    $scope.user1 = getModel('name', 'George');

    $scope.user2 = getModel('name', 'Michael');

    $scope.user3 = getModel('name', 'Joe');

    $scope.address = getModel('address');


  //You can improve this by passing an optional getter functionality as well for some specific evaluation on the value when set.
  function getModel(propertyName, defValue) {
      var obj =  {};

      obj._defVal = defValue;
      obj[propertyName] = function(newVal){
        if (angular.isDefined(newVal)) {
          obj[prop] = newVal;
        }
        return obj[prop];
      }

      return obj;
    }
   }

Or just

 function getModel(propertyName, defValue) {
      var obj =  {};
       var propValue = defValue;
      obj[propertyName] = function(newVal){
        if (angular.isDefined(newVal)) {
          propValue = newVal;
        }
        return propValue;
      }
      return obj;
    }
  }

Demo2

Share:
15,950
Chris Dunom
Author by

Chris Dunom

Updated on June 04, 2022

Comments

  • Chris Dunom
    Chris Dunom about 2 years

    I'm learning angular and I'm trying to figure out what is the best solution to use getters/setter.

    Saying, I'm using a library which exposes getters and setters (as Moment.js does).

    I've tried several ways to deal with getters and setters, here they are:

    index.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8" />
      <title>Example - example-ngModel-getter-setter-production</title>
      <script data-require="[email protected]" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.18/angular.min.js">    </script>
      <script src="app.js"></script>
    </head>
    
    <body ng-app="getterSetterExample">
      <div ng-controller="ExampleController">
        <form name="userForm">
          Name :
          <input type="text" name="userName" ng-model="user.name" ng-model-options="{ getterSetter: true }" />
          <br/>Name1:
          <input type="text" name="userName1" ng-model="user1.name" ng-model-options="{ getterSetter: true }" />
          <br/>Name2:
          <input type="text" name="userName2" ng-model="user2.name" ng-model-options="{ getterSetter: true }" />
          <br/>Name3:
          <input type="text" name="userName3" ng-model="user3.name" ng-model-options="{ getterSetter: true }" />
        </form>
        <pre>user.name =         <span ng-bind="user.name()"></span>
          </pre>
        <pre>user1.name =        <span ng-bind="user1.name()"></span>
          </pre>
        <pre>user2.name =        <span ng-bind="user2.name()"></span>
          </pre>
        <pre>user3.name =        <span ng-bind="user3.name()"></span>
          </pre>
      </div>
    </body>
    
    </html>
    

    app.js

      angular.module('getterSetterExample', [])
        .controller('ExampleController', ['$scope',
          function($scope) {
            var _name = 'Brian';
            var _name3 = 'Joe';
    
    
            var name1 = {
              _name: 'George',
              name:function(newName) {
                if (angular.isDefined(newName)) {
                  this._name = newName;
                }
                return this._name;
              }
            };
    
            var name2 = {
              _name: 'Michael',
              name:function(newName) {
                if (angular.isDefined(newName)) {
                  this._name = newName;
                }
                return this._name;
              }
            };
    
            var name3 = {
              name:function(newName) {
                if (angular.isDefined(newName)) {
                  _name3 = newName;
                }
                return _name3;
              }
            };
    
            $scope.user = {
              name: function(newName) {
                if (angular.isDefined(newName)) {
                  _name = newName;
                }
                return _name;
              }
            };
    
            $scope.user1 = {
              name: name1.name
            };
    
            $scope.user2 = {
              name: function(newName) {
                return name2.name(newName);
              }
            };
    
            $scope.user3 = {
              name: name3.name
            };
    
          }
        ]);
    

    You can try it here: http://plnkr.co/edit/S1qKre9umNpLOt0sjpZf?p=preview

    2 Questions:

    user1 tries to direcly use the getter/setter provided by the name1 objet, it doesn't work properly, can you explain why?

    Is there a way to avoid to rewrite a "proxy" for each getter/setter as I've done in user3? what would be the best method to use getters/setters provided by an external library?

    Thank for your help

  • Chris Dunom
    Chris Dunom almost 10 years
    I've a concern regarding the scope.You pointed that the mistake was the wrong scope during execution.I've tried to modify the code to include name2 into the scope like this: I replaced var name2 by $scope.name2 and modified index.html ng-model="name2.name". I was expecting to fix the scope issue by having this binded to the scope. Where is the mistake?
  • PSL
    PSL almost 10 years
    "You pointed that the mistake was the wrong scope during execution" Not really i meant wrong context pointed by this. I did not get what you mean. Can you paste your code in a plunker..
  • Chris Dunom
    Chris Dunom almost 10 years
    I've edited the code here plnkr.co/edit/3dh1DmGvIy6V7YPPEfKV?p=preview (8th version) -- look at line 20 in index.html and line 18 in app.js. I expected this to be binded to $scope at execution time.
  • PSL
    PSL almost 10 years
    @ChrisDunom Not really.. See the line from angular code if (ctrl.$options && ctrl.$options.getterSetter && isFunction(modelValue)) { modelValue = modelValue(); } Bascially the function reference is modelValue and it is just executed with no context. It is just the copy of function reference that is being executed. This is always the problem when we use this in the piece of code where we dont have a control over the execution context.
  • Chris Dunom
    Chris Dunom almost 10 years
    Thank you for the clarification.