Бұрыштық DOM-ға арналған аумақтық жаңартуларды қосу кезінде әдісті қалай іске қосуға болады?

Айнымалы $ айнымалы айнымалы мәнге өзгерістер енгізгеннен кейін, бұл жағдайда $ scope.results деп коды орындау жолын іздеймін. Міне, мұны орындау үшін DOM-дағы элементтерді талап ететін кейбір бұрынғы кодты қоңырау шалу үшін жасау керек.

Менің нақты кодым AJAX қоңырауын іске қосады және ui жаңарту үшін айнымалы айнымалы мәнді жаңартады. Сондықтан қазіргі уақытта менің кодым ауқымға итермелегеннен кейін бірден орындалады, бірақ бұрынғы код сәтсіздікке ұшырайды, өйткені домен элементтері әлі қол жетімді емес.

SetTimeout() көмегімен қате кідіріс қосуға болады, бірақ бұл DOM шынымен дайын екеніне кепілдік бермейді.

Менің сұрағым, «оқиға» ретінде қолданылатын кез келген тәсілдер бар ма?

var myApp = angular.module('myApp', []);

myApp.controller("myController", ['$scope', function($scope){
    var resultsToLoad = [{id: 1, name: "one"},{id: 2, name: "two"},{id: 3, name: "three"}];
    $scope.results = [];

    $scope.loadResults = function(){
        for(var i=0; i < resultsToLoad.length; i++){
            $scope.results.push(resultsToLoad[i]);
        }
    }

    function doneAddingToDom(){
       //do something awesome like trigger a service call to log
    }
}]);
angular.bootstrap(document, ['myApp']);

Link to simulated code: http://jsfiddle.net/acolchado/BhApF/5/

Алдын-ала рақмет!

35
Мен де осындай проблемаға тап болып жатырмын және менің ойларым 'awesome нәрсе жасау' уәдесін қолданып, $ watch ішіндегі айнымалы айнымалы мәнді орнатып, уақтылы жаңартып, . Мен мұны әлі көрген жоқпын: тек бұрыштыққа түсіп кету. Сіз оны жұмыс істей алатыныңызды білгім келеді!
қосылды автор Max, көзі
Мен де осындай проблемаға тап болып жатырмын және менің ойларым 'awesome нәрсе жасау' уәдесін қолданып, $ watch ішіндегі айнымалы айнымалы мәнді орнатып, уақтылы жаңартып, . Мен мұны әлі көрген жоқпын: тек бұрыштыққа түсіп кету. Сіз оны жұмыс істей алатыныңызды білгім келеді!
қосылды автор Max, көзі
SetTimeout() функциясын пайдаланғыңыз келсе, неге setInterval() әдісін қолданбайсыз? Бұрыштық жолмен, кодадағы сағаттардың функционалдығын пайдаланудың кез келген тәсілі бар ма?
қосылды автор Foyzul Karim, көзі
SetTimeout() функциясын пайдаланғыңыз келсе, неге setInterval() әдісін қолданбайсыз? Бұрыштық жолмен, кодадағы сағаттардың функционалдығын пайдаланудың кез келген тәсілі бар ма?
қосылды автор Foyzul Karim, көзі
SetTimeout пайдаланудан аулақ болғым келеді. Мен өзім қалаған нәрсені істеуге талпынатын бұл скрипка таптым, бірақ ол жұмыс істемейді. Кілт, $ evalAsync сияқты көрінеді, сондықтан оны жұмыс істеу жолын табуға тура келеді. Мен дұрыс жолмен жүремін деп үміттенемін.
қосылды автор acolchado, көзі
SetTimeout пайдаланудан аулақ болғым келеді. Мен өзім қалаған нәрсені істеуге талпынатын бұл скрипка таптым, бірақ ол жұмыс істемейді. Кілт, $ evalAsync сияқты көрінеді, сондықтан оны жұмыс істеу жолын табуға тура келеді. Мен дұрыс жолмен жүремін деп үміттенемін.
қосылды автор acolchado, көзі

9 жауаптар

The $evalAsync queue is used to schedule work which needs to occur outside of current stack frame, but before the browser's view render. -- http://docs.angularjs.org/guide/concepts#runtime

Жарайды, сондықтан «стек кадры» деген не? Github түсініктемесі келесідей:

Егер контроллерден сөз байласаңыз, ол бұрынғыдай болады, бірақ егер директиваға нұсқау берсеңіз, ол кейінірек болады. - https://github.com/angular/angular.js/issues/734 # issuecomment-3675158

Жоғарыда, Misko $ evalAsync арқылы орындау үшін кезекке қойылған кодты DOM бұрышпен жаңартылған кезде іске қосылған кезде талқылайды. Мен Github түсініктемелерін толық мәтінмәнді алу үшін оқып шығуды ұсынамын.

So if code is queued using $evalAsync from a directive, it should run after the DOM has been manipulated by Angular, but before the browser renders. If you need to run something after the browser renders, or after a controller updates a model, use $timeout(..., 0);

Сондай-ақ, $ evalAsync функциясын қолдана алатын мысал скрипті бар https://stackoverflow.com/a/13619324/215945 . ().

62
қосылды
@CMCDragonkai, өйткені Javascript біркелкі, бұрыштық жұмыс істегенде, шолғыш сіз көрген нәрсені жаңартпайды (яғни, ол көрсетілмейді). Тұжырымдар беті ішіндегі екінші суретті қараңыз. «DOM Render» бұрыштық қорытпа циклынан кейін орын алады. Мен алдымен $ evalAsync-ды қолдануға тырысамын, ал егер бұл жұмыс істемесе, мен $ timeout тырысамын.
қосылды автор Mark Rajcok, көзі
DOM жаңартылғаннан кейін браузер көрсеткен кезде не айтасыз? Браузер әрдайым болып жатқан нәрсені көрсете ме? Басқаша айтқанда, жолды диспетчерлік үлгідегі ата-ана ауқым үлгісінен асинхронды интерполяциядан кейін ғана іске асыруға болатын функцияны іске қосатын болсам, evalAsync немесе $ timeout қолданамын ба? Мен $ timeout қолданып жүрмін және ол жұмыс істеп жатыр, бірақ бұл нәрселердің дұрыс әдісі болып табылады ма?
қосылды автор CMCDragonkai, көзі
Түсіндіру үшін көп рахмет. $ EvalAsync() функциясы бар немесе жоқ, $ timeout (..., 0) пайдалану қажеттілігі бар. Мәжбүрлеп күтуді қосқан соң, ол өте жақсы жұмыс істеді. Енді браузер қоңыраудың орындалуына дейін көрсетуді аяқтайды.
қосылды автор acolchado, көзі

The $evalAsync queue is used to schedule work which needs to occur outside of current stack frame, but before the browser's view render. -- http://docs.angularjs.org/guide/concepts#runtime

Жарайды, сондықтан «стек кадры» деген не? Github түсініктемесі келесідей:

Егер контроллерден сөз байласаңыз, ол бұрынғыдай болады, бірақ егер директиваға нұсқау берсеңіз, ол кейінірек болады. - https://github.com/angular/angular.js/issues/734 # issuecomment-3675158

Жоғарыда, Misko $ evalAsync арқылы орындау үшін кезекке қойылған кодты DOM бұрышпен жаңартылған кезде іске қосылған кезде талқылайды. Мен Github түсініктемелерін толық мәтінмәнді алу үшін оқып шығуды ұсынамын.

So if code is queued using $evalAsync from a directive, it should run after the DOM has been manipulated by Angular, but before the browser renders. If you need to run something after the browser renders, or after a controller updates a model, use $timeout(..., 0);

Сондай-ақ, $ evalAsync функциясын қолдана алатын мысал скрипті бар https://stackoverflow.com/a/13619324/215945 . ().

62
қосылды
@CMCDragonkai, өйткені Javascript біркелкі, бұрыштық жұмыс істегенде, шолғыш сіз көрген нәрсені жаңартпайды (яғни, ол көрсетілмейді). Тұжырымдар беті ішіндегі екінші суретті қараңыз. «DOM Render» бұрыштық қорытпа циклынан кейін орын алады. Мен алдымен $ evalAsync-ды қолдануға тырысамын, ал егер бұл жұмыс істемесе, мен $ timeout тырысамын.
қосылды автор Mark Rajcok, көзі
DOM жаңартылғаннан кейін браузер көрсеткен кезде не айтасыз? Браузер әрдайым болып жатқан нәрсені көрсете ме? Басқаша айтқанда, жолды диспетчерлік үлгідегі ата-ана ауқым үлгісінен асинхронды интерполяциядан кейін ғана іске асыруға болатын функцияны іске қосатын болсам, evalAsync немесе $ timeout қолданамын ба? Мен $ timeout қолданып жүрмін және ол жұмыс істеп жатыр, бірақ бұл нәрселердің дұрыс әдісі болып табылады ма?
қосылды автор CMCDragonkai, көзі
Түсіндіру үшін көп рахмет. $ EvalAsync() функциясы бар немесе жоқ, $ timeout (..., 0) пайдалану қажеттілігі бар. Мәжбүрлеп күтуді қосқан соң, ол өте жақсы жұмыс істеді. Енді браузер қоңыраудың орындалуына дейін көрсетуді аяқтайды.
қосылды автор acolchado, көзі

I forked your fiddle. http://jsfiddle.net/xGCmp/7/

Мен эмит деп аталатын директиваны қостық. Бұл екі параметрді талап етеді. Шығарылатын іс-шара және оның шығарылуын қамтамасыз ету үшін қажет шарты. Бұл жұмыс сілтеме функциясының директивасында орындалған кезде, элемент DOM-да көрсетілгенін білеміз. Менің шешімім ng-қайталаудағы соңғы элемент болған кезде оқиға шығаруға арналған.

Егер бізде барлық бұрыштық шешім болса, мұны істеуге кеңес бермеймін. Бұл хакy тәрізді. Бірақ, сіз айтқан ескі кодтың түрін өңдеуге арналған тамаша шешім болуы мүмкін.

var myApp = angular.module('myApp', []);

myApp.controller("myController", ['$scope', function($scope){
    var resultsToLoad = [
        {id: 1, name: "one"},
        {id: 2, name: "two"},
        {id: 3, name: "three"}
    ];

    function doneAddingToDom() {
        console.log(document.getElementById('renderedList').children.length);
    }

    $scope.results = [];

    $scope.loadResults = function(){
        $scope.results = resultsToLoad;
       //If run doneAddingToDom here, we will find 0 list elements in the DOM. Check console.
        doneAddingToDom();
    }

   //If we run on doneAddingToDom here, we will find 3 list elements in the DOM.
    $scope.$on('allRendered', doneAddingToDom);
}]);

myApp.directive("emitWhen", function(){
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var params = scope.$eval(attrs.emitWhen),
                event = params.event,
                condition = params.condition;
            if(condition){
                scope.$emit(event);
            }
        }
    }
});

angular.bootstrap(document, ['myApp']);
5
қосылды
Егер сіз сұраған нәрсе осы скрипкамен сипатталған болса, онда иә. =) jsfiddle.net/h98pH/1
қосылды автор Benny Johansson, көзі
Бұл өте жақсы шешім. Оны шынымен бағалаңыз! Бір сұрақты жылдам қадағалаңыз. Егер бұл батырманы басқан сайын тізімнің соңына қосқан ленивый жүктелген тізім болса, оқиға әр уақытта жұмыстан шығарылсын ба?
қосылды автор acolchado, көзі

Менің директива болдым, сондықтан бұрыштамадан кейін барлық элементін іске қосқаннан кейін оны оқуы керек болатын директивадағы элементінің нәтижесінің height() </$ digest және браузер схемасын шығарды.

Директивімнің link функциясында;

Бұл жеткілікті кеш емес, сенімді жұмыс істемеді;

scope.$watch(function() {}); 

Бұл әлі жеткілікті кеш емес;

scope.$evalAsync(function() {});

ауқымымен ẁindow.setTimeout() қызығушылығын тудырған кезде $ (apply) () қолданылмады.

$timeout(function() {}, 0);

Соққылау мәселесі болса да, мен өзімнің директивамның ішіндегі $ timeout қалпына келтіру үшін requestAnimationFrame() пайдалануды ұсындым (сәйкесінше тиісті жеткізушілердің префикстерімен). Жеңілдетілген, бұл шын мәнінде көрінеді;

scope.$watch("someBoundPropertyIexpectWillAlterLayout", function(n,o) {
    $window.requestAnimationFrame(function() {
        scope.$apply(function() {
            scope.height = element.height();//OK, this seems to be accurate for the layout
        });
    });
});

Әрине, әрине, мен пайдалана аламын;

scope.$watch("height", function() {
   //Adjust view model based on new layout metrics
});
0
қосылды

Егер сіз мен сияқты болсаңыз, DOM-дың шынымен тұрақты және толығымен статикалық болмағандықтан, күту уақыты бар $ күту уақыты көптеген жағдайларда көп екенін байқайсыз. Мен DOM-дың тұрақты болуын қаласам, ол тұрақты болуын қалаймын. Міне, менің шешімім - «DOMSubtreeModified» оқиғасы үшін элементке бақылаушы орнату (немесе бүкіл құжаттың төмендегі мысалында). Мен 500 миллисекунд күтіп, DOM өзгерістері болмады, мен «domRendered» сияқты оқиғаны таратып беремін.

IE:

   //todo: Inject $rootScope and $window, 


   //Every call to $window.setTimeout will use this function
   var broadcast = function() {};

   if (document.addEventListener) {

       document.addEventListener("DOMSubtreeModified", function (e) {
           //If less than 500 milliseconds have passed, the previous broadcast will be cleared. 
           clearTimeout(broadcast)
           broadcast = $window.setTimeout(function() {
               //This will only fire after 500 ms have passed with no changes
               $rootScope.$broadcast('domRendered')
           }, 500)

       });

   //IE stupidity
   } else {
       document.attachEvent("DOMSubtreeModified", function (e) {

           clearTimeout(broadcast)
           broadcast = $window.setTimeout(function() {
               $rootScope.$broadcast('domRendered')
           }, 500)

       });
   }

Бұл оқиғаны барлық хабарлар секілді:

$rootScope.$on("domRendered", function(){
   //do something
})
0
қосылды

Таймаут пайдалану - бұл дұрыс жол. DOM қосу/басқару үшін директиваны пайдаланыңыз. Егер сіз тайм-аут пайдалансаңыз, бұрышпен байланысы бар $ timeout (мысалы, уәдені қайтарады) пайдалануды ұмытпаңыз.

0
қосылды

Таймаут пайдалану - бұл дұрыс жол. DOM қосу/басқару үшін директиваны пайдаланыңыз. Егер сіз тайм-аут пайдалансаңыз, бұрышпен байланысы бар $ timeout (мысалы, уәдені қайтарады) пайдалануды ұмытпаңыз.

0
қосылды

интервалы маған жұмыс істейді, мысалы:

interval = $interval(function() {
    if ($("#target").children().length === 0) {
        return;
    }
    doSomething();
    $interval.cancel(interval);
}, 0);
0
қосылды

интервалы маған жұмыс істейді, мысалы:

interval = $interval(function() {
    if ($("#target").children().length === 0) {
        return;
    }
    doSomething();
    $interval.cancel(interval);
}, 0);
0
қосылды