Obtain data of a promise in an Angular directive

3

I am working on a directive that needs information to work. This information must come from a promise. The problem is that the directive loads without the information because the promise takes more time to execute than the directive itself. Then my code:

angular.module('app').directive('tagInput', tagInput);

var tagInput = function ($timeout, profileService) {

  var profileList = profileService.getProfileList();

  profileList.then(function (profiles) {
    var profileObject = {};
    var profilesFiltered = [];

    for(var index in profiles){
      if(profiles[index].hasOwnProperty('id')){
        var notStandard = profiles[index].id.match(/\d+/g);
        if (notStandard != null) {
          profileObject.icon = '<i class="fa fa-bookmark" aria-hidden="true"></i>';
        }
        else{
          profileObject.icon = '<i class="fa fa-user" aria-hidden="true"></i>';
        }
        profileObject.name = profiles[index].name;
        profileObject.identifier = profiles[index].id;
        profileObject.ticked = false;
        profilesFiltered.push(profileObject);
      }
    }

    return profilesFiltered;
  });

return {
  restrict: 'EA',
  require: 'ngModel',
  scope: {
    tags: '=ngModel',
    searchParams: '=searchParams'
  },
  replace: false,
  link: function ( scope, element, attrs ) {

    scope.modelFilter = {
      showSearchPanel: false,
      inputProfiles: profilesFiltered,
    }
    ...
}

This way the data in the template always appear null. How can I prepare the data before executing the link in the directive. You may need something very similar for inputAccounts: accountsFiltered, .

    
asked by AndreFontaine 22.09.2016 в 23:25
source

1 answer

2

You should not worry about that. Angular is designed so that once the data arrives they update the view automatically. If you must put content you can put a loader or something similar.

By definition an http request, promise or future value is impossible to know when it will end or if it will end at all so it is not a good idea to delay the compilation of the directive, it only compiles and updates the data in $scope when you have them.

Looking at the code of your directive I see that you try to obtain the data in the same moment in which the directive is being declared which is an error because the directives have several phases where you can / must put execution code.

1 compile      => No tiene $scope. No podrás actualizar la vista
2 controller   => Tiene $scope. Ocurre primero que el pre y el post
3 pre-link     => Tiene $scope. Ocurre primero que el pre de las directivas hijas
4 post-link    => Tiene $scope. Ocurre después que el post de las directivas hijas

These are executed in that same order. In your case you already have a post-link so you can use it to put all the logic there.

It would be something like that

angular.module('app').directive('tagInput', tagInput);

var tagInput = function($timeout, profileService) {
  return {
    restrict: 'EA',
    require: 'ngModel',
    scope: {
      tags: '=ngModel',
      searchParams: '=searchParams'
    },
    replace: false,
    link: function(scope, element, attrs) {

      // Inicializas el objeto
      scope.modelFilter = {
        showSearchPanel: false,
        inputProfiles: []
      }

      profileService.getProfileList().then(function(profiles) {
        var profileObject = {};
        var profilesFiltered = [];

        for (var index in profiles) {
          if (profiles[index].hasOwnProperty('id')) {
            var notStandard = profiles[index].id.match(/\d+/g);
            if (notStandard != null) {
              profileObject.icon = '<i class="fa fa-bookmark" aria-hidden="true"></i>';
            } else {
              profileObject.icon = '<i class="fa fa-user" aria-hidden="true"></i>';
            }
            profileObject.name = profiles[index].name;
            profileObject.identifier = profiles[index].id;
            profileObject.ticked = false;
            profilesFiltered.push(profileObject);
          }
        }

        // Actualizas el objeto con los resultados obtenidos. 
        // La vista se actualizará automaticamente
        scope.modelFilter.inputProfiles = profilesFiltered;
      });
    }
  }
}

If you need to call the promise code again, you encapsulate it in a function so that it can be reused.

This way, it does not matter when your results arrive, since your view will always be updated.

    
answered by 26.09.2016 в 15:33