programing

AngularJS : 필터를 비동기적으로 초기화합니다.

lovejava 2023. 10. 1. 19:01

AngularJS : 필터를 비동기적으로 초기화합니다.

비동기 데이터로 필터를 초기화하는 데 문제가 있습니다.

필터는 매우 간단해서 이름으로 경로를 변환해야 하지만 그러기 위해서는 서버에서 가져와야 하는 대응 배열이 필요합니다.

함수를 반환하기 전에 필터 정의의 작업을 수행할 수는 있지만 비동기적인 측면은 이를 방지합니다.

angular.module('angularApp').
  filter('pathToName', function(Service){
    // Do some things here

    return function(input){
      return input+'!'
    }
  }

약속을 사용하는 것이 실행 가능할 수도 있지만, 저는 필터의 각도 부하가 어떻게 되는지에 대해 명확한 이해를 하지 못합니다.게시물은 서비스로 그러한 마법을 달성하는 방법을 설명하고 있습니다만, 필터에 대해서도 같은 방법이 가능합니까?

그리고 그 길들을 번역하는 방법에 대해 더 좋은 생각을 가진 사람이 있다면, 저는 귀를 쫑긋 세우고 있습니다.

편집:

약속을 지키려고 노력했지만 뭔가가 잘못되었고 무엇이 있는지 알 수가 없습니다.

angular.module('angularApp').filter('pathToName', function($q, Service){

  var deferred = $q.defer();
  var promise = deferred.promise;

  Service.getCorresp().then(function(success){
    deferred.resolve(success.data);
  }, function(error){
    deferred.reject();
  });

  return function(input){
    return promise.then(
      function(corresp){
        if(corresp.hasOwnProperty(input))
          return corresp[input];
        else
          return input;
      }
    )
  };
});

저는 약속을 잘 모르는데, 사용하는 방법이 맞나요?

다음은 예입니다.

app.filter("testf", function($timeout) {
    var data = null, // DATA RECEIVED ASYNCHRONOUSLY AND CACHED HERE
        serviceInvoked = false;

    function realFilter(value) { // REAL FILTER LOGIC
        return ...;
    }

    return function(value) { // FILTER WRAPPER TO COPE WITH ASYNCHRONICITY
        if( data === null ) {
            if( !serviceInvoked ) {
                serviceInvoked = true;
                // CALL THE SERVICE THAT FETCHES THE DATA HERE
                callService.then(function(result) {
                    data = result;
                });
            }
            return "-"; // PLACEHOLDER WHILE LOADING, COULD BE EMPTY
        }
        else return realFilter(value);
    }
});

바이올린은 서비스 대신 타임아웃을 사용하는 시연입니다.


편집: 스기메노의 지적에 따르면, 서비스를 한 번 이상 호출하지 않은 것에 대해 각별히 주의해야 합니다.참조.serviceInvoked위의 코드와 바이올린의 변화.값을 변경하고 다이제스트 사이클을 트리거하려면 각 1.2.1을 사용하는 포크 피들과 버튼을 참조하십시오.


편집 2: Miha Er žen의 코멘트에 따르면, 이 솔루션은 Angular 1.3에서는 로그너가 작동하지 않습니다.그러나 솔루션은 거의 사소합니다.$stateful여기 "Stateful filters" 아래에 문서화된 필터 플래그와 필요한 포크 피들.

필터를 각 다이제스트 사이클(digest cycle)이라고 부르기 때문에 이 솔루션은 성능을 저하시킨다는 에 유의하십시오.성능 저하는 특정한 경우에 따라 무시할 수도 있고 그렇지 않을 수도 있습니다.

왜 원래의 코드가 작동하지 않는지 이해하는 것부터 시작하겠습니다.좀 더 명확하게 하기 위해 원래 질문을 조금 단순화했습니다.

angular.module('angularApp').filter('pathToName', function(Service) {

    return function(input) {
        return Service.getCorresp().then(function(response) {
            return response;
        });
    });

}

기본적으로 필터는 약속을 반환하는 비동기 함수를 호출한 다음 값을 반환합니다.각도로 표시된 필터는 문자열 또는 숫자와 같이 쉽게 인쇄할 수 있는 값을 반환합니다.그런데 이 경우에는 반환하는 것처럼 보여도.responsegetCorresp, 우리는 실제로 새로운 약속을 반환하고 있습니다 - 모든 것의 반환 가치.then()아니면catch()기능은 약속입니다.

Angular가 캐스팅을 통해 약속 개체를 문자열로 변환하려고 하면 아무것도 인식되지 않고 빈 문자열이 표시됩니다.


따라서 임시 문자열 값을 반환하고 다음과 같이 비동기적으로 변경해야 합니다.

JSFiddle

HTML:

<div ng-app="app" ng-controller="TestCtrl">
    <div>{{'WelcomeTo' | translate}}</div>
    <div>{{'GoodBye' | translate}}</div>
</div>

자바스크립트:

app.filter("translate", function($timeout, translationService) {

    var isWaiting = false;
    var translations = null;

    function myFilter(input) {

        var translationValue = "Loading...";
        if(translations)
        {
            translationValue = translations[input];
        } else {
            if(isWaiting === false) {
                isWaiting = true;
                translationService.getTranslation(input).then(function(translationData) {
                    console.log("GetTranslation done");
                    translations = translationData;
                    isWaiting = false;
                });
            }
        }

        return translationValue;
    };

    return myFilter;
});

Angular가 필터를 실행하려고 할 때마다 번역이 이미 가져온 것인지 확인하고 그렇지 않은 경우 "로딩.."을 반환합니다." 값어치를 보다우리는 또한 사용합니다.isWaiting서비스를 두 번 이상 호출하지 않도록 하는 값입니다.

위의 예는 Angular 1.2에 대해서는 잘 작동하지만 Angular 1.3의 변화 중 필터의 거동을 변화시키는 성능 개선이 있습니다.이전에는 필터 함수를 매 다이제스트 사이클이라고 불렀습니다.를 호출합니다.는 필터를 호출하지 않습니다.나 1.3합니다. 마지막 샘플에서는 다시는 필터를 호출하지 않습니다.'WelcomeTo'변하지 않을 겁니다

다행히도 해결 방법은 매우 간단합니다. 필터에 다음 사항을 추가하면 됩니다.

JSFiddle

myFilter.$stateful = true;

마지막으로 이 문제를 처리하는 동안 또 다른 문제가 생겼습니다. 변경할 수 있는 비동기 값을 얻기 위해 필터를 사용해야 했습니다. 특히 단일 언어에 대한 번역을 가져와야 했지만 사용자가 언어를 변경한 후에는 새 언어 집합을 가져와야 했습니다.그렇게 하는 것은, 비록 개념은 같지만, 조금 더 까다롭다는 것을 증명했습니다.이 코드는 다음과 같습니다.

JSFiddle

var app = angular.module("app",[]);
debugger;

app.controller("TestCtrl", function($scope, translationService) {
    $scope.changeLanguage = function() {
        translationService.currentLanguage = "ru";
    }
});

app.service("translationService", function($timeout) {
    var self = this;

    var translations = {"en": {"WelcomeTo": "Welcome!!", "GoodBye": "BYE"}, 
                        "ru": {"WelcomeTo": "POZHALUSTA!!", "GoodBye": "DOSVIDANYA"} };

    this.currentLanguage = "en";
    this.getTranslation = function(placeholder) {
        return $timeout(function() {
            return translations[self.currentLanguage][placeholder];
        }, 2000);
    }
})

app.filter("translate", function($timeout, translationService) {

    // Sample object: {"en": {"WelcomeTo": {translation: "Welcome!!", processing: false } } }
    var translated = {};
    var isWaiting = false;

    myFilter.$stateful = true;
    function myFilter(input) {

        if(!translated[translationService.currentLanguage]) {
            translated[translationService.currentLanguage] = {}
        }

        var currentLanguageData = translated[translationService.currentLanguage];
        if(!currentLanguageData[input]) {
            currentLanguageData[input] = { translation: "", processing: false };
        }

        var translationData = currentLanguageData[input];
        if(!translationData.translation && translationData.processing === false)
        {
            translationData.processing = true;
            translationService.getTranslation(input).then(function(translation) {
                console.log("GetTranslation done");
                translationData.translation = translation;
                translationData.processing = false;
            });
        }

        var translation = translationData.translation;
        console.log("Translation for language: '" + translationService.currentLanguage + "'. translation = " + translation);
        return translation;
    };

    return myFilter;
});

언급URL : https://stackoverflow.com/questions/19046641/angularjs-asynchronously-initialize-filter