Knockoutjs: ajout de propriétés et de fonctions observables aux objets dans une cartographie générée par observable
-
28-10-2019 - |
Question
Je suis nouvelle Knockoutjs, et je suis coincé en essayant d'ajouter des propriétés et des méthodes supplémentaires aux objets générés dans le ko.observableArray()
comme créé par le mapping
brancher.
Voici où je vais:
- J'ai une gamme JSON de
Users
- J'ai créé le
ko.observableArray()
avec le plugin de cartographie - J'ai un modèle qui crée une ligne de table pour chaque
User
, jusqu'ici tout va bien: o)
Voici ce que j'essaie de faire:
Chaque User
a une propriété appelée 'IsActive'
- Je voudrais data-bind
un événement de clic sur une méthode sur chaque User
objet qui bascule ceci 'IsActive'
propriété.
Cette question semblait prometteuse, mais cela me semble être une duplication inutile de devoir déclarer le modèle de vue entier dans JS (à moins que ce ne soit ainsi que je dois le faire!) - Est-il possible d'étendre l'objet généré?
Je pensais plus dans ce sens, où il existe un moyen de déclarer des propriétés ou des méthodes supplémentaires, et leur faire étendre le mapping
objets générés, mais cet article concerne les objets uniques plutôt que d'extenser des objets dans un tableau généré.
Voici le code: http://jsfiddle.net/yzksf/2/ (Ne fonctionnant pas encore dans JS Fiddle - mais je continuerai à jouer avec et à mettre à jour ce lien lorsque je le ferai fonctionner).
Merci de votre aide
La solution
Il existe plusieurs options que vous pourriez considérer.
-Un est d'utiliser le create
rappeler Pour contrôler la façon dont vos objets "utilisateur" sont créés. Vous pouvez soit définir les observables vous-même et ajouter des fonctionnalités supplémentaires, soit appeler le plugin de mappage sur l'objet utilisateur individuel, puis ajouter des fonctionnalités supplémentaires.
Serait quelque chose comme: http://jsfiddle.net/rniemeyer/fkvak/
-Lu encore, vous pouvez placer la fonction "Toggle" sur votre vue ViewModel, puis y transmettre l'objet "utilisateur".
Une belle façon avec 1,3, c'est utiliser ko.dataFor
Parallèlement à quelque chose comme la fonctionnalité en direct / déléguée / sur la délégation des événements de JQuery. Serait comme: http://jsfiddle.net/rniemeyer/fkjnr/
//unobtrusive event handler
$(".toggle").live("click", function() {
var user = ko.dataFor(this);
if (user) {
viewModel.toggleIsActive(user);
}
});
Si vous ne souhaitez pas utiliser la délégation d'événements, vous pouvez passer l'élément directement à l'aide d'une fonction anonyme comme: http://jsfiddle.net/rniemeyer/gpqtn/
EDIT: à partir de 2.0, les données actuelles sont automatiquement transmises au gestionnaire lors de l'utilisation de liaisons de clic / événement, vous pouvez donc simplement faire:
<a href="#" data-bind="click: $root.toggleIsActive"><span data-bind="text: IsActive"></span></a>
Autres conseils
C'est ce que j'ai trouvé en utilisant les réponses de vos et de Ryan ... semble fonctionner. Veuillez laisser les commentaires, car je suis nouveau à Knockout et moi moi-même, si c'est une bonne approche.
JS:
$(function() {
$.get("users/getUsers", function(r){
var vm = ko.mapping.fromJS(r, {
users: {
create: function(user){
var methods = {
toggleIsActive: function(u){u.IsActive(!u.IsActive());},
foo: function(u){console.log(u);},
bar: function(u){/*whatever*/},
}
return $.extend(ko.mapping.fromJS(user.data), methods);
}
}
});
ko.applyBindings(vm);
}, 'json');
});
DOM:
<!-- ko foreach: users -->
<a href="#" data-bind="click: toggleIsActive"><span data-bind="text: IsActive"></span></a>
<!-- /ko -->
J'ai trouvé un moyen de le faire, mais cela signifie faire une boucle à travers les objets générés dans le tableau une fois qu'ils ont été créés. Je préférerais un moyen d'obtenir le même résultat sans la boucle supplémentaire.
ÉDITER: Comme RP Niemeyer le suggère dans sa réponse! ; o)
Quoi qu'il en soit, une façon d'ajouter des propriétés à un objet existant est d'utiliser jQuery Extend () pour combiner les objets.
Tout d'abord, déclarez les propriétés et fonctions supplémentaires dans un nouvel objet:
var userModel = {
toggleIsActive: function() {
console.log('toggleIsActive called: before: ' + this.IsActive());
this.IsActive(!this.IsActive());
// todo: save!
console.log('toggleIsActive called: after: ' + this.IsActive());
}
}
Ensuite, après le ko.mapping.fromJS()
appel, Mais avant le ko.applyBindings()
appel, faire une boucle à travers les objets dans le tableau généré et les étendre:
viewModel.users = ko.mapping.fromJSON(/* get JSON */);
for (var i = 0; i < viewModel.users().length; i++) {
$.extend(viewModel.users()[i], userModel);
}
ko.applyBindings(viewModel);