Lier des données modales de knock-out modèle
Je suis d'essayer d'avoir un twitter bootstrap modal ouvrir une fenêtre qui comporte une zone de texte qui est modifiable, puis sur enregistrer, il enregistre les données appropriées. Mon code actuel:
HTML:
<table class="display table table-striped">
<tbody data-bind="foreach: entries">
<tr>
<td>
Placeholder
</td>
<!-- ko foreach: entry_data -->
<td>
<div class="input-group">
<input type="text" class="form-control col-sm-2" data-bind="value: entry_hours">
<span class="input-group-addon"><a class="comment" data-bind="click: function() { $root.modal.comment($data); $root.showModal(); }, css: { 'has-comment': comment.length > 0, 'needs-comment': comment.length == 0 }, attr: { title: comment }"><span class="glyphicon glyphicon-comment"></span></a></span>
</div>
</td>
<!-- /ko -->
</tr>
</tbody>
</table>
<!-- Modal template -->
<script id="commentsModal" class="modal-dialog" type="text/html">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-bind="click:close" aria-hidden="true">×</button>
<h4 data-bind="html:header" class="modal-title"></h4>
</div>
<div class="modal-body">
<textarea class="form-control" rows="3" data-bind="value: $root.modal.comment.comment"></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-bind="click:close,html:closeLabel">Close</button>
<button type="button" class="btn btn-primary" data-bind="click:action,html:primaryLabel" id="save-changes">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</script>
<!-- Create a modal via custom binding -->
<div data-bind="bootstrapModal:modal" class="modal fade" id="commentsModal" tabindex="-1" role="dialog" data-keyboard="false" data-backdrop="static"></div>
JS:
/* Custom binding for making modals */
ko.bindingHandlers.bootstrapModal = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var props = valueAccessor(),
vm = bindingContext.createChildContext(viewModel);
ko.utils.extend(vm, props);
vm.close = function() {
vm.show(false);
vm.onClose();
};
vm.action = function() {
vm.onAction();
}
ko.utils.toggleDomNodeCssClass(element, "modal fade", true);
ko.renderTemplate("commentsModal", vm, null, element);
var showHide = ko.computed(function() {
$(element).modal(vm.show() ? 'show' : 'hide');
});
return {
controlsDescendantBindings: true
};
}
}
var entriesdata = [{"entry_id":"51794","project_id":"2571","user_id":"89","entry_data":[{"entry_data_id":"359192","entry_id":"51794","entry_hours":"0.00","entry_date":"2013-12-22","comment":""},{"entry_data_id":"359193","entry_id":"51794","entry_hours":"8.00","entry_date":"2013-12-23","comment":"Test comment"},{"entry_data_id":"359194","entry_id":"51794","entry_hours":"8.00","entry_date":"2013-12-24","comment":"Test comment"},{"entry_data_id":"359195","entry_id":"51794","entry_hours":"0.00","entry_date":"2013-12-25","comment":""},{"entry_data_id":"359196","entry_id":"51794","entry_hours":"8.00","entry_date":"2013-12-26","comment":"Test comment"},{"entry_data_id":"359197","entry_id":"51794","entry_hours":"8.00","entry_date":"2013-12-27","comment":"Test comment"},{"entry_data_id":"359198","entry_id":"51794","entry_hours":"0.00","entry_date":"2013-12-28","comment":""}]}];
var projectsdata = [{"project_txt":"Test Project","project_id":12345}];
var TimeEntriesModel = function(entries, projects) {
var self = this;
self.projects = ko.observableArray(projects);
self.entries = ko.observableArray(ko.utils.arrayMap(entries, function(entry) {
return {
entry_id : entry.entry_id,
project_id : entry.project_id,
user_id : entry.user_id,
entry_data : ko.observableArray(entry.entry_data)
}
}));
self.save = function () {
ko.utils.stringifyJson(self.entries);
}
self.modal = {
header: "Add/Edit Comment",
comment: ko.observableArray([{comment: "test"}]),
closeLabel: "Cancel",
primaryLabel: "Save",
show: ko.observable(false), /* Set to true to show initially */
onClose: function() {
self.onModalClose();
},
onAction: function() {
self.onModalAction();
}
}
console.log(ko.isObservable(self.modal.comment));
self.showModal = function() {
self.modal.show(true);
}
self.onModalClose = function() {
//alert("CLOSE!");
}
self.onModalAction = function() {
//alert("ACTION!");
self.modal.show(false);
}
}
ko.applyBindings(new TimeEntriesModel(entriesdata, projectsdata));
Violon: http://jsfiddle.net/sL3HK/
Comme vous pouvez le voir dans le violon, la modale s'ouvre avec la zone de texte, mais je suis incapable de comprendre comment obtenir le "commentaire" de texte dans le modal ou de mettre à jour le commentaire lorsque le bouton "enregistrer" est pressé.
Des idées?
Aussi, je suis très nouveau à élimination directe, donc si il y a quelque chose qui ne vous convient pas, n'hésitez pas à me corriger sur elle.
Mise à JOUR:
J'ai été de jongler avec le code, et ont été en mesure d'obtenir le "commentaire" dans le modal, mais je n'ai pas réussi à le mettre à jour jusqu'à ce point. Et un autre problème, je vais finir par rencontrer, c'est que je ne veux le commentaire à être mis à jour lorsque "Enregistrer" est cliqué, plutôt que la normale mise à jour sur le flou. Je pense vraiment que je vais sur ce mal, mais je ne suis pas sûr de ce que l' droit façon est. Plus l'aide est grandement appréciée.
Vous devez vous connecter pour publier un commentaire.
Ici est un JsFiddle dans lequel vous devriez être en mesure de modifier le commentaire pour chaque entrée. Voici comment j'ai procédé pour obtenir ce.
Le Viewmodel
Tout d'abord, je tiens à diviser mon point de vue en partiels. Pour chaque type de partiels, j'ai créer un ViewModel. Et un "niveau supérieur" ViewModel est utilisé comme un conteneur pour tous les partiels Viewmodel. Ici, vous aurez besoin d'un EntryDataViewModel lequel j'ai défini de cette façon :
Fondamentalement, ce constructeur ne la conversion de vos données brutes pour quelque chose que vous serez en mesure de manipuler à votre point de vue. Selon ce que vous voulez faire, vous pouvez faire des choses observables ou non.
comment
est utilisé dans de certaines liaisons et devrait changer. Nous voulons la page de réagir de façon dynamique à l'évolution de son, nous allons donc rendre observable.En raison de ce changement, nous allons changer la façon dont nous créons le "niveau supérieur" ViewModel (ici
TimeEntriesModel
), et en particulier :Maintenant notre Viewmodel sont prêts à être mis à jour. Donc, nous allons changer le modal.
Le Modal
De nouveau, dans le modal, le
comment
sera sujet à changement, et nous voulons récupérer sa valeur (pour mettre à jour notre EntryData). Donc, c'est un fait observable.Maintenant, nous devons informer le modal dont EntryData nous sommes en train de modifier (et je pense que c'est la partie principale de votre code manquait). Nous pouvons le faire en gardant une référence de la EntryData qui a été utilisé pour ouvrir le modal :
Dernière chose à faire est de mettre à jour l'ensemble de ces variables lorsque vous ouvrez le modal :
Et lorsque vous enregistrez :
Conclusion
Je n'ai pas envie de changer tous vos fixations et le code, donc il y avait beaucoup de petits changements et je pense que vous aurez à jouer avec le code pour voir comment ils affectent le comportement de la page, la façon dont il fonctionne. Ma solution n'est pas parfaite bien sûr. Il reste un peu de logique dans votre balisage HTML qui doit être déplacée vers le JS et je ne suis pas sûr que vous avez vraiment besoin de toute la liaison personnalisée choses. De plus, je ne suis pas heureux à ce sujet modal. Le modal choses doivent appartenir à un
EntryDataViewModel
depuis l'édition du commentaire actes sur un EntryData, mais comme je l'ai dit, je n'ai pas envie de changer tout votre code. Dites-moi si vous avez des problèmes avec ma solution :).Mise à jour (quelques astuces pour aller plus loin)
Quand j'ai dit "déplacement de la logique à partir de code HTML JS", voici ce que je voulais dire. La suite de la liaison semble compliqué d'appartenir à des balises HTML.
Certaines choses que vous pouvez faire : déplacer
$root.modal.comment(comment())
àshowModal
, puis de cliquer sur la liaison devientclick : $root.showModal
. Même les "besoins-commentaire" la liaison a une logique, vous pourriez ajouter une méthodeneedsComment
à votreEntryDataViewModel
que contient cette logique.Gardez à l'esprit que les balises HTML ne doit pas contenir toute logique, il devrait simplement faire des appels de fonctions JS. Si une fonction agit sur une partielle de la vue (par exemple, un EntryData), alors cette fonction appartient à la vue partielle du modèle (c'est pourquoi j'ai eu à se plaindre du modal, qui agit sur un seul EntryData mais ici se trouve dans le
TimesEntriesModel
). Si une fonction manipule un ensemble d'éléments (par exemple, si vous créez un bouton "ajouter"), cette fonction appartient dans le conteneur ViewModel.Ce fut une TRÈS longue réponse spécifique. Excuses pour cette. Vous devriez être capable de trouver beaucoup de ressources sur le Model View ViewModel (MVVM) sur le web, qui vous aideront dans votre voyage 🙂
ko.utils.stringifyJson(self.entries)
je récupérer l'entrée principale de données (saisie de l'id, l'id de projet, id d'utilisateur) à la place de l'information ainsi que les données pour les entrées réelles qui va avec chacun d'eux maintenant. Est-il un moyen de corriger ça?ko.toJSON(self.entries)
semble fonctionner pour moi. Dites-moi si cela peut vous aiderEntryDataViewModel
.entryDataViewModel
est implicitement passé lors de l'appel deshowModal
? J'ai essayé de passer les choses pour ces fonctions, quand il ne me semble pas que j'ai réellement besoin de tous. J'ai effectivement pris le CSS un peu plus loin et consolidés dans un seul calculé en fonction: jsfiddle.net/Qyqve/3$data
) et de l'objet d'événement. En fait, j'ai pu également utiliser lathis
mot-clé ici, mais je n'aime pas utiliserthis
trop en JS comme il est la source de beaucoup d'erreurs. Utilisez votre navigateur pour les développeurs d'outils pour voir comment knock-out se comporte avec les liaisons. Si vous utilisez google Chrome, je vous recommande le plugin "knock-out Contexte Débogueur".Pour ce que ça vaut, j'ai écrit le
ko-modale
projet de faire des modaux plus facile de travailler avec lors de l'utilisation de knock-out.Serions heureux de recevoir de la rétroaction sur elle, et en tout cas j'espère que c'est utile de regarder.