2017-07-22 1 views
0

Résumé: J'ai un observable contrôlant un élément de page de chargement qui masque tout lors d'une requête longue. La page de chargement ne s'affiche pas même si l'observable est modifiée avant la requête. Mettre un espace réservé setTimeout fonctionne, mais la page semble attendre que la requête s'exécute pour mettre à jour la page.Knockout: Chargement de la page en attente de fin d'une requête

Édition 3: Je dois mentionner que je le fais dans Node.js.

Edit2: Ce que je veux arriver:

1) l'utilisateur clique sur le bouton.
2) Chargement des couvertures de l'écran.
3) Les calculs exécutés
4) écran de chargement disparaît et table est remplie avec les résultats

Ce qui se passe actuellement:
1) l'utilisateur clique sur le bouton.
2) L'écran se fige pendant 3 à 4 secondes lorsque les calculs sont exécutés.
3) Le tableau est rempli avec les résultats

Explication Nous avons une des requêtes en cours d'exécution couple à long ish sur notre page (dure environ 3-4 secondes), et nous voulons mettre un écran de chargement jusqu'à masquer les commandes et informer les gens que la page est en cours d'exécution.

Voici un extender j'ai écrit (avec l'aide de l'Internet):

ko.bindingHandlers.Loading = { 
init: function (element) { 
    $(element).append("<div id='loading_wrap' class='loader' style='height:100%; width:100%;text-align:center; margin-top: 20%'><img src='./resources/ajax-loader.gif'><br>Loading, please wait.</div>") 
}, 
update: function (element, valueAccessor) { 
    var isLoading = ko.utils.unwrapObservable(valueAccessor()); 
    var $element = $(element); 
    var $children = $element.children(':not(.loader)'); 
    var $loader = $(element).find('.loader'); 

    if (isLoading) { 
     $children.hide(); 
     $loader.show(); 
    } else { 
     $children.show(); 
     $loader.hide(); 

    } 
} 

Je joins le bindingHandler à un div contenant les résultats que je veux me cacher jusqu'à ce qu'ils soient prêts:

<div class="row table__row" data-bind="Loading:isLoading"> 

J'ai défini this.isLoading (true) avant d'exécuter la requête, puis de la redéfinir sur false après la requête. Ce qui suit ne fonctionne pas:

this.load = _ => { 
     var _self = this 
     this.isLoading(true) 
     this.search() 
     this.isLoading(false) 
    } 

Toutefois, si je mets un délai d'attente, la page de chargement s'affiche correctement. J'ai aussi essayé quelques méthodes asynchrones, mais je ne comprends pas très bien cela. Alors, comment faire apparaître la page de chargement avant l'exécution de la requête, puis disparaître une fois la requête terminée? Merci.

Editer: Vous avez des questions sur la recherche. Il ressemble à ceci (nous ne sommes pas en utilisant Ajax)

this.search = async _ => { 
//bunch of filters/calculations on large arrays 
this.results(the results of our large calculations) 
} 
+1

utilisez-vous ajax pour vos questions? Si oui, pourriez-vous le définir dans la méthode beforesend ajax? –

+0

juste dire "... ne fonctionne pas" est un peu trop large, froid s'il vous plaît affiner? Si vous utilisez ajax, veuillez fournir le code de votre méthode asynchrone. – deblocker

+0

Merci à tous pour vos réponses rapides: Non, nous n'utilisons pas Ajax, j'ai une fonction Javascript qui fait quelques calculs. (Je ne suis pas sûr de ce que la terminologie correcte est). Il faut environ 3-4 secondes pour que les calculs puissent être exécutés. Il ressemble 'this.search = _ => {// groupe de filtres sur les grands tableaux // calculs // défini certaines valeurs observableArray }' –

Répondre

1

L'utilisation d'un gestionnaire de liaison est pas strictement nécessaire que vous avez des actions que dans une seule direction.

Keep it simple:

this.isLoading.subscribe(function(value) { 
    ... get elements 
    $children.toggle(!value); 
    $loader.show(value); 
}); 

Après votre commentaire, je crois que ce que vous avez besoin est juste de reporter légèrement le long travail de course, après la fileuse de chargement a été montré, quelque chose comme ça:

this.isLoading(true); 
    setTimeout(function() { 
     this.search(); 
     this.isLoading(false); 
    }, 100); 

Voici un article sur la différence entre les promesses et le code asynchrone: https://stackoverflow.com/a/20930199/4845566

BTW, voici les références knock-out fo r extenders et ici pour binding handlers.

+0

Merci pour la réponse. J'essaie de rendre cet écran de chargement disponible pour d'autres pages, pas seulement pour la page sur laquelle je travaille. En utilisant un bindingHandler a semblé le rendre facile à attacher sur un DIV, mais je peux également faire la même chose pour un extendeur? –

+0

IMHO votre approche serait grande si vous avez plus d'un spinner de chargement dans une page, sinon l'approche consolidée consiste à mettre l'emballage de chargement dans le balisage avec une [liaison visible] (http://knockoutjs.com/documentation/visible- binding.html) – deblocker

+0

BTW, maintenant votre question semble totalement différente maintenant. Êtes-vous sûr que votre appel asynchrone à un calcul synchrone lourd se comportera comme vous vous y attendez? Je crois que vous avez de toute façon attendre que le calcul de blocage synchrone à l'intérieur de l'appel asynchrone soit terminé ... juste remis à plus tard. Pas clair pour moi quel devrait être le flux de travail en utilisant 'async' ici. pourriez-vous s'il vous plaît expliquer? – deblocker