32 votes

intégration du dialogue jquery ui avec knockoutjs

Je suis en train de créer knockoutjs liaisons pour jquery ui boîtes de dialogue, et ne peut pas obtenir la boîte de dialogue ouvrir. La boîte de dialogue de l'élément est créé correctement, mais semble avoir display: none que l'appelant dialog('open') n'est pas supprimer. Aussi, l'appel à l' dialog('isOpen') retourne la boîte de dialogue objet plutôt qu'un booléen.

Je suis en utilisant la dernière knockoutjs et jquery 1.4.4 avec jquery ui 1.8.7. J'ai aussi essayé avec jQuery 1.7.1 avec les mêmes résultats. Voici mon code HTML:

<h1 class="header" data-bind="text: label"></h1>

<div id="dialog" data-bind="dialog: {autoOpen: false, title: 'Dialog test'}">foo dialog</div>

<div>
    <button id="openbutton" data-bind="dialogcmd: {id: 'dialog'}" >Open</button>
    <button id="openbutton" data-bind="dialogcmd: {id: 'dialog', cmd: 'close'}" >Close</button>
</div>

et c'est le javascript:

var jQueryWidget = function(element, valueAccessor, name, constructor) {
    var options = ko.utils.unwrapObservable(valueAccessor());
    var $element = $(element);
    var $widget = $element.data(name) || constructor($element, options);
    $element.data(name, $widget);

};

ko.bindingHandlers.dialog = {
        init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
            jQueryWidget(element, valueAccessor, 'dialog', function($element, options) {
                console.log("Creating dialog on "  + $element);
                return $element.dialog(options);
            });
        }        
};

ko.bindingHandlers.dialogcmd = {
        init: function(element, valueAccessor, allBindingsAccessor, viewModel) {          
            $(element).button().click(function() {
                var options = ko.utils.unwrapObservable(valueAccessor());
                var $dialog = $('#' + options.id).data('dialog');
                var isOpen = $dialog.dialog('isOpen');
                console.log("Before command dialog is open: " + isOpen);
                $dialog.dialog(options.cmd || 'open');
                return false;
            });
        }        
};

var viewModel = {
    label: ko.observable('dialog test')
};

ko.applyBindings(viewModel);

J'ai mis en place un JSFiddle qui reproduit le problème.

Je me demande si cela a quelque chose à voir avec knockoutjs et la gestion des événements. J'ai essayé de revenir true à partir du gestionnaire de clic, mais qui ne semble pas affecter quoi que ce soit.

58voto

RP Niemeyer Points 81663

Il ressemble à l'écriture pour le widget .de données("dialogue"), puis en essayant de travailler sur celle-ci est à l'origine d'un problème. Voici un exemple où l' .data n'est pas utilisé et l'ouverture/fermeture est appelé basée sur l'élément: http://jsfiddle.net/rniemeyer/durKS/

Sinon, j'aime travailler avec la boîte de dialogue de manière un peu différente. J'aime contrôler si la boîte de dialogue est ouverte ou fermée à l'aide d'une observable. Ainsi, vous souhaitez utiliser une liaison unique sur le dialogue lui-même. L' init serait d'initialiser la boîte de dialogue, tandis que l' update serait de vérifier un fait observable pour voir si elle doit appeler l'ouvrir ou le fermer. Maintenant, l'ouverture/fermeture boutons juste besoin de passer un booléen observables plutôt que de s'inquiéter de papiers d'identité ou la localisation du dialogue.

ko.bindingHandlers.dialog = {
        init: function(element, valueAccessor, allBindingsAccessor) {
            var options = ko.utils.unwrapObservable(valueAccessor()) || {};
            //do in a setTimeout, so the applyBindings doesn't bind twice from element being copied and moved to bottom
            setTimeout(function() { 
                options.close = function() {
                    allBindingsAccessor().dialogVisible(false);                        
                };

                $(element).dialog(options);          
            }, 0);

            //handle disposal (not strictly necessary in this scenario)
             ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
                 $(element).dialog("destroy");
             });   
        },
        update: function(element, valueAccessor, allBindingsAccessor) {
            var shouldBeOpen = ko.utils.unwrapObservable(allBindingsAccessor().dialogVisible),
                $el = $(element),
                dialog = $el.data("uiDialog") || $el.data("dialog");

            //don't call open/close before initilization
            if (dialog) {
                $el.dialog(shouldBeOpen ? "open" : "close");
            }  
        }
};

Utilisé comme:

<div id="dialog" data-bind="dialog: {autoOpen: false, title: 'Dialog test' }, dialogVisible: isOpen">foo dialog</div>

Voici un exemple: http://jsfiddle.net/rniemeyer/SnPdE/

4voto

eselk Points 1796

L'ajout de cette ici parce que c'est ce que la plupart des gens à trouver lors de la recherche sur les questions de avec jQuery UI Dialog knock-out et JS.

Juste une autre option pour éviter la "double liaison" problème expliqué dans la réponse ci-dessus. Pour moi, le setTimeout() était à l'origine d'autres liaisons à l'échec qui nécessitent la boîte de dialogue pour être initialisé déjà. La solution simple qui a fonctionné pour moi a été d'apporter les modifications suivantes à la accepté de répondre:

  1. Ajouter class='dialogue' pour tous les éléments à l'aide de la boîte de dialogue personnaliser la liaison.

  2. Appel cet après chargement de la page, mais avant l'appel de ko.applyBindings():

    $('.boîte de dialogue').dialog({autoOpen: false});

Supprimer l' setTimeout à l'intérieur de l' init de la liaison personnalisée, et il suffit d'appeler directement le code.

L'étape 2 permet de s'assurer que tout jQuery UI boîtes de dialogue ont été initialisé avant tout KO liaisons. De cette façon, jQuery UI a déjà les éléments du DOM, de sorte que vous n'avez pas à vous soucier de se déplacer dans le milieu de applyBindings. Le code d'initialisation travaille toujours comme-est (autres que de retirer setTimeout) parce que la boîte de dialogue() va juste mettre à jour une boîte de dialogue si déjà initialisé.

Pourquoi, par exemple, j'avais besoin de cela est dû à une liaison personnalisée-je utiliser pour mettre à jour le titre de la boîte de dialogue:

ko.bindingHandlers.jqDialogTitle = {
    update: function(element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).dialog('option', 'title', value);
    }
};

J'utilise une liaison séparée pour cela à la place de la fonction de mise à jour de la boîte de dialogue principale de liaison, parce que je ne veux mettre à jour le titre, pas d'autres propriétés telles que la hauteur et la largeur (ne veux pas la boîte de dialogue redimensionner juste parce que j'ai changer le titre). Je suppose que je pourrais aussi utiliser la mise à jour et d'effacer hauteur/largeur, mais maintenant, je peux faire les deux/et ne pas vous soucier de setTimeout ou pas.

4voto

bysanches Points 61

J'ai légèrement modifié la réponse de RP Niemeyer pour permettre aux options de la boîte de dialogue d'être observables

http://jsfiddle.net/YmQTW/1/

Obtenez les valeurs de variables observables avec ko.toJS pour initialiser le widget

 setTimeout(function() { 
    options.close = function() {
        allBindingsAccessor().dialogVisible(false);                        
    };

    $(element).dialog(ko.toJS(options));          
}, 0);
 

et vérifier les observables sur la mise à jour

 //don't call dialog methods before initilization
if (dialog) {
    $el.dialog(shouldBeOpen ? "open" : "close");

    for (var key in options) {
        if (ko.isObservable(options[key])) {
            $el.dialog("option", key, options[key]());
        }
    }
}
 

2voto

juuxstar Points 21

Il y a maintenant cette bibliothèque qui contient toutes les liaisons JQueryUI pour KnockoutJS, y compris, bien sûr, le widget de dialogue.

2voto

JotaBe Points 8950

C'est une variante de la grande RP Niemeyer liaison gestionnaire, ce qui est utile pour une differente scénario.

Pour permettre l'édition d'une entité, vous pouvez créer un <div> avec édition des contrôles, et d'utiliser un with de liaison, qui dépend d'une observable faite exprès pour l'édition.

Par exemple, pour permettre l'édition d'un person, vous pouvez créer et observables comme editedPerson, et de créer un div avec édition des contrôles, avec une liaison comme ceci:

data-bind="with: editedPerson"

Lorsque vous ajoutez une personne à l'observable lke donc:

vm.editedPerson(personToEdit);

la liaison fait l' div visible. Lorsque vous avez terminé l'édition, vous pouvez définir les propriétés observables null, comme

vm.editedPerson(null);

et l' div va se fermer.

Mon variation de RP Niemeyer bindingHandler permet d'afficher automatiquement à l'intérieur de ce div jQuery dialogue de l'INTERFACE utilisateur. Pour l'utiliser, il vous suffit de conserver l'original with de liaison, et de spécifier le jQuery UI boîte de dialogue options comme:

data-bind="with: editedPerson, withDialog: {/* jQuery UI dialog options*/}"

Vous pouvez obtenir le code de mon gestionnaire de liaison, et de le voir en action ici:

http://jsfiddle.net/jbustos/dBLeg/

Vous pouvez modifier ce code facilement avoir par défaut différente pour le dialogue, et même de faire ces valeurs par défaut configurable en joignant le gestionnaire dans un js module, et l'ajout d'un public de configuration de la fonction à modifier. (Vous pouvez ajouter cette fonction à la liaison de gestionnaire, et il continuera à travailler).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X