0

I want to change ng-model(degree) value to id(degree_id) in my template as following

<md-select flex class="md-select-form" ng-model="education.degree" placeholder="Degree" save-id required-param="{{education.degree_id}}">
 <md-option ng-value="degree" ng-repeat="degree in ['High School', 'Associates Degree', 'Bachelor Degree', 'Masters Degree', 'M.B.A', 'M.D', 'Ph.D', 'other']">{{degree}}</md-option>
</md-select>

I have used the directive(save-id) for this parsing in my controller and i have pulled degree service data and binding the relevant id.The code is following

    .directive('saveId', function(Profile){
        return {
            require: 'ngModel',
            scope: {
                requiredParam:'@'
            },        
            link: function(scope, element, attrs, ngModel) {
                console.log("initial loading");
                // view --> model (change to string)            
                ngModel.$parsers.push(function(viewValue){
                    var id = -1;
                    var keepGoing = true;                
                    Profile.getDegreeList().then(function(data) {
                        angular.forEach(data, function(ob){
                            if(keepGoing) {
                                if(ob.degree == viewValue){
                                    id = ob.degree_id;
                                    keepGoing = false;
                                }
                            }
                        });
                        //console.log(id); // it gives updated value
                    });
                    console.log(id); // it gives -1       
                    return id;

                });

            }
        };
    })

I have updated the model value as mentioned above the problem is ,Only the updated value is available within

Profile.getDegreeList(){ }

Out of this function the value is -1 , what's wrong here? Please give me the solutions??

user3391137
  • 431
  • 8
  • 26
  • What are you trying to do exactly? I think it's odd that your directive would return something in it's `link` block. – Spikee Dec 07 '15 at 09:45
  • Could you provide a Plunk (or other source) of what you're trying to achieve? It's hard to grasp what you're trying to do. – Spikee Dec 07 '15 at 10:33
  • Consider this plunk: http://plnkr.co/edit/oDHyEp4YNlgEGpdZrsvp?p=preview What else do you require? – Spikee Dec 07 '15 at 12:42
  • actually i need to change that value to id bro – user3391137 Dec 07 '15 at 14:20
  • Which value do you mean? Would it be possible to fork that Plunk and add to it to reflect what you need (doesn't have to work)? – Spikee Dec 07 '15 at 14:25
  • i need to change the ng-model value to selected item'id than keeps it as that value tha's why i have used the directory in my post code bro – user3391137 Dec 07 '15 at 14:32
  • i have used ngModel.$parsers.push(function(viewValue){}) for it – user3391137 Dec 07 '15 at 14:34
  • I'm sorry, I don't understand the requirements you mention, could you clarify? Right now I'm under the impression that you're making things unnecessarily complex. – Spikee Dec 07 '15 at 14:36
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/97204/discussion-between-user3391137-and-spikee). – user3391137 Dec 07 '15 at 14:37
  • please see this link http://stackoverflow.com/questions/34132574/how-to-execute-the-statement-after-promise-is-executed/34132615#34132615 – user3391137 Dec 07 '15 at 14:41

2 Answers2

0

Profile.getDegreeList() returns a promise that is evaluated asynchronously. You register some code that is executed when the promise is resolved. Within this code the id is set. However, the line

console.log(id);

that immediately follows the creation of the promise is executed before the promise is resolved.

If you want to process the id further, or pass it to another function you have to do it within the promise. This means that the line

ngModel.$parsers.push(...) 

has to be pulled into the function that is called when the promise is resolved (i.e. the function passed to then())

lex82
  • 11,173
  • 2
  • 44
  • 69
  • Yah bro i have identified the issue.. however i want to return the id at the end of ngModel.$parsers.push(). how to solve? – user3391137 Dec 07 '15 at 10:03
  • it seems as you are said problem is because of Profile.getDegreeList() asynchronously execution. do you have any way(context) of execute the code of console.log(id) after the promise has successfully completed? – user3391137 Dec 07 '15 at 10:19
  • The function passed to the .then() method of your promise is the only context in which you can work with the value. You cannot block until the promise is resolved. – lex82 Dec 07 '15 at 10:30
0

It's because your call to Profile.getDegreeList() is asynchronous.

The console.log(id) outside the getDegreeList block is executed immediatelly meaning it logs it's defined value of -1.

The console.log(id) inside the getDegreeList block does work, because at that point the data is loaded.

You should work with promises ($q).

I'm not sure what you're trying to do, but put simply, the following would work: can easily use the option value attribute to assign the id value to drop-down rather than going through directive.

 <select ng-model="education.degree.id" id="degreeList">
    <option 
      value="{{degree.id}}" 
      ng-selected="{{education.degree == degree}}" 
      ng-repeat="degree in degrees">
        {{degree.name}}
    </option>
  </select>

And in your controller (for example)

 .controller("myController", [
  "$scope",
  "$http",
  function($scope, $http){
    var self = {};

    $scope.education = {
      degree: {
        id: -1,
        name: ""
      }
    };

    $scope.degrees = 
    [
      {
        id: 1,
        name: 'High School'
      }, 
      {
        id: 2,
        name: 'Associates Degree'
      }, 
      {
        id: 3,
        name: 'Bachelor Degree'
      }, 
      {
        id: 4,
        name: 'Masters Degree'
      }, 
      {
        id: 5,
        name: 'M.B.A'
      }, 
      {
        id: 6,
        name: 'M.D'
      }, 
      {
        id: 7,
        name: 'Ph.D'
      }, 
      {
        id: 8,
        name: 'other'
      }];
  }]);
Spikee
  • 3,967
  • 7
  • 35
  • 68
  • Updated the script to use `$scope.id`. That's the easiest solution, not knowing exactly what you're trying to achieve. – Spikee Dec 07 '15 at 09:46
  • $scope mean which is isolated scope of directive no? – user3391137 Dec 07 '15 at 09:52
  • Yes, unless it's a parameter provided to the `directive` by a binding in it's `scope` definition. – Spikee Dec 07 '15 at 09:54
  • i have tried this one bro it updates value but updates wrongly it means updates the value which is previously selected one in drop-down.. – user3391137 Dec 07 '15 at 09:54
  • If you use it like this: `scope: { id: '=', requiredParam:'@' }` `` ? Using the above script, your outside variable `model.someId´ should get updated automatically through two-way binding. – Spikee Dec 07 '15 at 09:56
  • this is what? it's my one? – user3391137 Dec 07 '15 at 09:59
  • I overlooked it earlier, but since you're directive is called `saveId`, it's ``. – Spikee Dec 07 '15 at 10:01
  • i have used as attribute like , you're saying to attach the id like rght? – user3391137 Dec 07 '15 at 10:06
  • As an extension to an attribute, yup! Should work. Sidenote, if `md-select` is yours as well, I'd build it in directly into that, rather than extend your own tag (unless other requirements would force you, ofcourse). – Spikee Dec 07 '15 at 10:07
  • still it updates wrong value(updates the value which is previously selected one in drop-down) – user3391137 Dec 07 '15 at 10:11
  • Could you provide a Plunk (or something else) for a full sample? – Spikee Dec 07 '15 at 10:14
  • it seems as you are said problem is because of Profile.getDegreeList() asynchronously execution. do you have any way(context) of execute the code of console.log(id) after the promise has successfully completed? – user3391137 Dec 07 '15 at 10:19
  • My above answer would do it. I don't see why you would need to chain the promise, because it would be strange to return anything in the `.link`. If you need to return something, you should put it in a `service` instead. – Spikee Dec 07 '15 at 10:23
  • because i need to take the ids for the drop-down menus from service that's why i'm pulling the service – user3391137 Dec 07 '15 at 10:27
  • If I understand you correctly, in that case it should be in the `controller`. Either directly, or by consuming a `service`. – Spikee Dec 07 '15 at 10:30
  • The actual thing i need to do is as i mentioned in this post i want to change the ng-model model value as id from string, The ng-model contain the drp-down string value when user selects and save the form drop-down should give the id than name. for it i used that directive to change the model value – user3391137 Dec 07 '15 at 10:38
  • I think you're making things too complex that way, which is why I'm asking for a sample. Easier to suggest specific corrections that way. – Spikee Dec 07 '15 at 10:42
  • And to detect the selected item id i have pulled that service which contains id and item name values. – user3391137 Dec 07 '15 at 10:42