4

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

0

1 Answer 1

4

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

Sign up to request clarification or add additional context in comments.

4 Comments

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?
"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..
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.
@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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.