Как передать функцию через атрибут директивы, сохраняя исходную ссылку «this»

#angularjs #angularjs-directive #angular-directive

#angularjs #angularjs-директива #angular-директива

Вопрос:

Я разработал директиву для загрузки файлов в Angular. Я хотел бы передать успешный обратный вызов из родительского компонента в директиву, но он ссылается this на эту функцию, которая теряется по пути.

Как мне поступить .bind(this) в этом случае?

Шаблон родительского компонента:

 <input
   type="file"
   name="xml-file"
   class="hidden"
   id="xml-file-input"
   accept="text/xml"
   file-upload
   file-upload-accept="text/xml"
   file-upload-then="$ctrl.fileUploadOnSuccess"
   file-upload-url="/versementPublique/{{ $ctrl.noDemande }}/dossiers">
  

директива загрузки файла:

 function FileUploadDirective(dialogBoxService, glossaryFilter, $parse, fileUploadService) {
  return {
    restrict: 'A',
    link(scope, elem, attrs) {
      const name = attrs.name;
      const url = attrs.fileUploadUrl;
      const type = attrs.fileUploadAccept;
      const successCallback = $parse(attrs.fileUploadThen)(scope);

      elem.on('change.upload', validate);

      function validate($event) {
        const errors = validateFile($event.target.files[0]);
        const isValid = errors.length === 0;

        if (!isValid) {
          dialogBoxService.open({
            title: glossaryFilter('erreur'),
            message: `
              Please correct the following:
              <ul class="list list--bullet">
                ${errors.map(err => `<li>${err}</li>`)}
              </ul>
            `,
          });
          scope.$apply();
          resetFileInput();
        } else {   
          const file = $event.target.files[0];
          const fd = new FormData();

          fd.append(name, file);

          this.coreService.http({
            method: 'POST',
            url: url,
            data: fd,
            transformRequest: angular.identity,
            headers: {
              'Content-Type': undefined,
            },
          })
          .then(then, catcher, notify);
        }
      }

      ...

      function then(response) {
        resetFileInput();
        successCallback();
      }

      function catcher(err) {
        console.error(err);
        resetFileInput();
      }

      function notify(event) {
        console.log(event);
      }

      function resetFileInput() {
        elem
          .off('change.upload')
          .val('')
          .on('change.upload', fileUploadService.uploadFile);
      }
    },
  };
}
  

Функция, переданная атрибуту:

 class ParentComponent {
  constructor($rootScope) {
     this.$rootScope = $rootScope;
  }

  // Because there is a `this` in here, when it is called in the
  // directive, it is lost. There is no way to .bind() in the
  // template, so I'm lost as how to keep the right `this`.
  fileUploadOnSuccess() {
    this.$rootScope.$broadcast('updateDossier');
  }
}

ParentComponent.$inject = ['$rootScope'];
  

Ошибка в консоли:

Поскольку this всегда вызывается функция (если вы .bind() ее не используете), она не может найти свойство $rootScope в классе, в котором оно определено.

Я пробовал привязку this в шаблоне, но это не работает.

Как я мог это сделать?

 gouvernementales.js:5328 Uncaught TypeError: Cannot read property '$rootScope' of undefined
  

Ответ №1:

Итак, вот как я смог решить свою this проблему:

Вызывая функцию, которая возвращает функцию, которая была привязана к «локальному» this, я смог сохранить правильную ссылку один раз внутри директивы.

Успешный обратный вызов, переданный директиве через атрибут:

 fileUploadOnSuccess() {
    return function success() {
      this.$rootScope.$broadcast('updateDossier');
    }.bind(this);
  }
  

Шаблон:

 <input
    type="file"
    name="fileDossiers"
    class="hidden"
    id="xml-file-input"
    accept="text/xml"
    file-upload
    file-upload-accept="text/xml"
    file-upload-then="$ctrl.fileUploadOnSuccess()"
    file-upload-url="/versementPublique/dossiers">