Quand utiliser ko.utils.unwrapObservable?

114

J'ai écrit quelques liaisons personnalisées à l'aide de KnockoutJS. Je ne sais toujours pas quand utiliser ko.utils.unwrapObservable(item)En regardant le code, cet appel vérifie essentiellement si itemc'est une observable. Si c'est le cas, retournez la valeur (), si ce n'est pas le cas, renvoyez simplement la valeur. En regardant la section sur Knockout sur la création de liaisons personnalisées, elles ont la syntaxe suivante:

var value = valueAccessor(), allBindings = allBindingsAccessor();
var valueUnwrapped = ko.utils.unwrapObservable(value);

Dans ce cas, ils invoquent l'observable via ()mais appellent ensuite ko.utils.unwrapObservable. J'essaie juste de savoir quand utiliser l'un par rapport à l'autre ou si je dois toujours suivre le modèle ci-dessus et utiliser les deux.

arb
la source

Réponses:

142

Vous devriez utiliser ko.utils.unwrapObservabledans les cas où vous ne savez pas si vous avez reçu un observable ou non. Ce serait généralement dans une liaison personnalisée où un observable ou non observable pourrait être lié à lui.

Dans le code que vous avez ci-dessus, l'appel à valueAccessor()ne déballe pas réellement un observable. Il récupère simplement la valeur qui a été passée à la liaison dans le bon contexte (elle est enveloppée dans une fonction pour la protéger). La valeur de retour de valueAccessor()peut être observable ou non. C'est tout ce qui a été passé à la liaison.

RP Niemeyer
la source
4
Cela dépend vraiment de la situation. Certaines liaisons personnalisées sont conçues pour ne fonctionner qu'avec des observables, vous pouvez donc vérifier à l'avance (ko.isObservable) qu'il s'agit d'un observable et vous seriez alors libre de le dérouler avec (). Si vous recevez un objet qui peut avoir des observables imbriqués, alors vous feriez mieux de faire une ko.toJS(yourObject)plutôt que d'utiliser ko.utils.unwrapObservable, si vous essayez d'obtenir une version non emballée de l'objet à passer dans un widget ou une bibliothèque tierce. En général, il est plus sûr à utiliser ko.utils.unwrapObservablepour prendre en charge les observables et les non-observables.
RP Niemeyer
2
Je suppose que je ne sais pas quel est le but ko.utils.unwrapObservable. En regardant le code, il vérifie simplement s'il est observable et si c'est le cas, Knockout invoque ()pour obtenir la valeur de l'observable, sinon, il renvoie simplement la valeur de non-observable. Si tout ce qui m'intéresse est la valeur des données transmises dans la liaison, pourquoi ne puis-je pas toujours l'utiliser ()?
arb
17
Vous ne savez pas si vous obtenez un observable ou un non-observable dans une liaison. Dites que j'ai myBindinget que quelqu'un se lie, c'est-à-dire comme data-bind="myBinding: myValue". myValuepeut être une observable ou simplement une propriété simple sur le modèle de vue. Si ce n'est qu'une propriété et que je l'appelle comme une fonction, vous obtiendrez une erreur. ko.utils.unwrapObservablevous renverra en toute sécurité la valeur indépendamment du fait que vous ayez passé une observable ou non.
RP Niemeyer
10
Je recommanderais également d'utiliser le raccourci «ko.unwrap» car «ko.utils.unwrapObservable» est une très longue expression.
Ivan Nikitin
3
@IvanNikitin - bien sûr, je voulais juste souligner qu'il ko.unwrapest disponible dans 3.0+. Si vous utilisez une version antérieure à 3.0, alors ko.utils.unwrapObservableest toujours là.
RP Niemeyer
12

La réponse précédente est correcte, mais je passe souvent des fonctions à des liaisons personnalisées (une fonction qui vérifie les autorisations ou détermine quoi faire en fonction de quelque chose d'autre, etc.). Ce dont j'avais vraiment besoin, c'était de dérouler n'importe quelle fonction, même si ce n'est pas une fonction observable.

Ce qui suit déballe TOUT de manière récursive:

ko.utils.unwrapFunction = function (func) {
    if (typeof func != 'function') {
        return func;
    }
    else {
        return ko.utils.unwrapFunction(func());
    }
};

Voici un exemple de liaison personnalisée simple que j'ai écrite:

//replaces single and double 'smart' quotes users commonly paste in from word into textareas and textboxes with normal text equivalents
//USAGE:
//data-bind="replaceWordChars:true
//also works with valueUpdate:'keyup' if you want"

ko.bindingHandlers.replaceWordChars = {
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var bindingValue = ko.utils.unwrapFunction(valueAccessor);

        if (bindingValue) {
            $(element).val(removeMSWordChars(allBindingsAccessor().value())); //update DOM - not sure why I should need to do this, but just updating viewModel doesn't always update DOM correctly for me
            allBindingsAccessor().value($(element).val()); //update viewModel
        }
    }
}

De cette façon, bindingValue contient toujours une valeur. Je n'ai pas à me soucier de savoir si j'ai passé une fonction, une observable, une valeur ou même une fonction à l'intérieur d'un observable. Cela déroulera correctement tout jusqu'à ce qu'il atteigne l'objet que je veux.

J'espère que cela aide quelqu'un.

pilavdzice
la source