I want to update one observable of one viewModel from another. The value gets changed but it does not reflect on UI (in HTML)
I am not sure what's wrong with the code..
Here is the code :
http://jsfiddle.net/rahulrulez/RSL4u/2/
<p data-bind="text: name"></p>
does not gets updated.
You are binding to two independent view-model instances
ko.applyBindings(new viewModel1(), document.getElementById("firstViewModel"));
ko.applyBindings(new viewModel2(), document.getElementById("secondViewModel"));
So there is no connection between your viewModel1 and viewModel2 and when you write in your viewModel1:
var vm2Object = new viewModel2();
then you are creating a completly new viewModel2 instance which has nothing to do with the one used in the applyBindings.
To fix this you need to make a connection between your view models, somehow like this (there are multiple other ways to do like using a container view model, nest your view models to each other, etc.):
var viewModel1 = function(vm2){
var self = this;
var vm2Object = vm2; //use vm from parameter
//...
}
And when calling the applyBindings:
var vm2 = new viewModel2();
ko.applyBindings(new viewModel1(vm2), document.getElementById("firstViewModel"));
ko.applyBindings(vm2, document.getElementById("secondViewModel"));
Demo JSFiddle.
You have two different instances of the VM2 ViewModel. Instead do
http://jsfiddle.net/RSL4u/4/
I have made VM2 a sub model of VM1
this.vm2Object = new viewModel2();
I tried all your approaches, for some reason they were not really working with the solution I have.
After a lot of googling and digging deep in KnockoutJS documentations and extensions, I found Knockout Postbox which lets us sync or communicate between multiple irrelevant View Models.
https://github.com/rniemeyer/knockout-postbox
Here is snippet of my demo example...
var viewModel1 = function(){
var _self = this;
_self.name = ko.observable("Rahul").syncWith("syncedName");
}
var viewModel2 = function(){
var _self = this;
_self.firstName = ko.observable("Rahul").syncWith("syncedName");
}
ko.applyBindings(new viewModel1(), document.getElementById("div1"));
ko.applyBindings(new viewModel1(), document.getElementById("div2"));
Both the observable are in sync now.. I found this much better than nesting objects.. At least it satisfied the need of my application..
Thank you so much for help anyway..
My Demo : JSFiddle : http://jsfiddle.net/rahulrulez/2kuSh/1/
I hope it helped..
Thank you so much,
Rahul Patil.
Related
I over complicated things at first and could not figure out how to create a list within a list using backbone.js. I finally got it, by simply creating a list item view for all of the players in my app. Then created a view for all of the teams inside my app.
I "glued" or "appended" them together by creating an app view that put them together, there is an each statement for both, before the two views were appended to the app view root, I appended the player list item view into the team view. Let me show you.
Here is my render method inside the app view: I am just not sure if this is a bad idea or not, I am thinking there are much better ways, but this is the only method I have had success with. It really makes sense to me, I can run events on each view without a problem
render: function() {
var self = this;
this.teams.each(function(team) {
var teamView = new TeamView({ model: team });
var teamHtml = teamView.render().el;
var teamPlayers = this.players.where({team_id: team.get('id')})
_.each(teamPlayers, function(player) {
var playerView = new PlayerView({ model: player });
var playerHtml = playerView.render().el;
$(teamHtml).append(playerHtml);
}, this);
this.$el.append(teamHtml);
}, this);
return this;
},
I asked about this and was told it would be better to create sub-views, well I am pretty sure this is a sub-view structure? Are there any holes to this method, if so I would like an explanation why this method is bad and how I can improve it. Last but not least I do care about clean maintainable code but what matters most is that I have teams wrap its respected players with an HTML result like below.
<div>
<ul class="lakers">
<li>Kobe</li>
<li>Pau</li>
</ul>
<ul class="spurs">
<li>Tony</li>
<li>Tim</li>
</ul>
</div>
Again id like some constructive criticism, mainly PROS & CONS with connecting the two views like that. Just needed to ask before I move on I want to make sure I am not getting into bad habits or creating problems in my code when I start expanding it, I am sure you understand that.
I asked about this and was told it would be better to create sub-views, well I am pretty sure this is a sub-view structure?
Yes you knew it, and TeamView is sub-view. However it's a "zombie view". Does it do anything itself? A view should be responsible of rendering itself, including appending its direct sub-views, but without knowing how to render its sub-views, i.e., you should pass the players collection to the TeamView and move the following logic into TeamView:
var teamPlayers = this.players.where({team_id: team.get('id')})
_.each(teamPlayers, function(player) {
var playerView = new PlayerView({ model: player });
var playerHtml = playerView.render().el;
$(teamHtml).append(playerHtml);
}, this);
I started learning OOP in JavaScript at school and I have to do my homework in OOP. It is a shopping list, one fills in a product and price and that is put into an array, the array its contents are put in a table in HTML. The list also has got delete buttons for every product, I have thought about using this in JavaScript, as I am working in OOP, but I am sceptic because of the scope.
The idea is that one clicks "verwijder" on the webpage (EDIT: in the corresponding row) and the table row is gone. I have thought about using this but also about dynamically updating the table after removing the selected row from the array.
Who can advise me about what to do and how to do that correctly?
I have uploaded my JavaScript here: http://jsfiddle.net/hNAZ9/
If you want to study oop in javascript (and you are allowed to use frameworks), my suggestion is to learn a framework like http://knockoutjs.com/ . The separation between view/html interaction code and js object modeling code will make you life much easier. Here is an example reimplementation of your fiddle, using knockout: http://jsfiddle.net/kaGzz/3/
I think it's a lot clearer what the objects are doing:
var Item = function(product, price, parentArray){
var self = this;
self.product = ko.observable(product);
self.price = ko.observable(price);
self.deleteItem = function(){
parentArray.remove(self);
}
}
var ShoppingList = function(){
var self = this;
self.currentProduct = ko.observable();
self.currentPrice = ko.observable();
self.items = ko.observableArray();
self.addItem = function(){
self.items.push(new Item(self.currentProduct(), self.currentPrice(), self.items));
}
}
var shoppingList = new ShoppingList();
I am building an SPA and everything is going well. It has multiple Viewmodels which are built dynamically and there can be multiple of the same kind, i.e you can open two calculators each having its own model which is bound to a specific div on the page.
Recently I realized that several of the viewmodels were requesting the same data from a web service and on a constant loop every 30 secs - 1 minute. So the same service call was being made multiple times every 30 seconds yet returning the same information.
So what I am trying to figure out is how I can create a "global" observableArray which multiple viewModels can be notified of a change and update rather than doing it themselves, this also helps to make sure the data on the page is consistent.
I was hoping I could do something like:
var GlobalData = (function() {
var commonData = ko.observableArray();
setInterval(function() {...go get data...commonData(data);}, 30000);
return {CommonData:commonData}
})();
ko.applyBindings(GlobalData, $('#RandomLonelyDiv')[0]);
Then later
function Calculator(element){
function init() { ko.applyBindings(calculator, $(element)[0]); }
var calculator = {
CommonData = GlobalData.CommonData
}
return calculator;
}
If it helps the only reason why I dont have a MainViewModel which contains all my other viewmodels is because i frankly dont know how to set that up for my environment.
I have a AppViewModel which contains a ko.observableArray called Windows, which is contains objects which define the options/information to build certain window types.
<!-- ko template:{name:'WindowTemplate', foreach:SelectedTab().Windows} --><!-- /ko -->
and then I have a custom Window binding that creates a modified kendoWindow, which creates a new viewmodel of a specific type such as Calculator, and like I said you could have multiple calculators at one time. But when I started this I wasnt really sure how to put that viewmodel into my AppViewModel. Perhaps its just another array?
It sounds like what you really need is a "Pub/Sub" model. That would allow you to publish and subscribe to messages that are ignorant of their generation or destination. Check out https://github.com/postaljs/postal.js/wiki.
I believe this may be what you are looking for: http://jsfiddle.net/xSKyR/474/
You can subscribe to another viewmodel's observable like so..
var ViewModel1 = function () {
var self = this;
self.something1 = ko.observable("1");
self.clickMe = function (data, event) {
self.something1("2");
};
};
var ViewModel2 = function () {
var self = this;
self.something2 = ko.observable();
vm1.something1.subscribe(function (newValue) {
self.something2(newValue);
});
};
var vm1 = new ViewModel1();
var vm2 = new ViewModel2();
ko.applyBindings(vm1, document.getElementById("vm1"));
ko.applyBindings(vm2, document.getElementById("vm2"));
This question is based on my previous one Switching from a region to another in Marionette, views are not rendered correctly. It differs from it since I'm asking if the approach I'm following is correct or it exists another approach to perform the switching between regions.
I've created a layout with two different regions. On initialize the layout loads two views in two regions of my layout. Say ViewA and ViewB. Within ViewA an event is triggered. The event is consumed by the layout to switch and other two views are injected. Say ViewC and ViewD.
Is this approach correct or do I have to follow another pattern? Routing?
Here some code where comments highlight the important parts.
onConfirm : function() {
this.leftView = new ViewC();
this.rightView = new ViewD();
this.leftRegion.show(this.leftView);
this.rightRegion.show(this.rightView);
},
initialize : function() {
// listen for event triggered from ViewA
// e.g. GloabalAggregator.vent.trigger("ga:confirm");
// where "ga:confirm" is a simple string
GloabalAggregator.vent.on("ga:confirm" , this.onConfirm, this);
this.leftView = new ViewA(), // creating here a new ViewC the style is applied correctly
this.rightView = new ViewB(); // creating here a new ViewD the style is applied correctly
},
onRender : function () {
this.leftRegion.show(this.leftView);
this.rightRegion.show(this.rightView);
}
To switch between views in a Layout usually a Controller is used, have a look at this gist for an example.
Basically you will have to create a new controller
var controller = Marionette.Controller.extend({
initialize: function(options){
this.leftRegion = options.leftRegion;
this.rightRegion = options.rightRegion;
},
swap: function() {
// do the region swapping here
}
});
You could create it like this from the view:
var controller = new MyController({
leftRegion: this.leftRegion,
rightRegion: this.rightRegion
});
(where this referes to the view) and have it listen on that event with the help of listenTo.
A couple more examples from the author of Marionette you might find useful:
fiddle
wiki article
I have an app that uses several different view models (this is the first time I have built an app with knockout js).
Basically what I'm doing is a wizard and each page is a knockout view model, at the end I'd like to take all the json from all the view models and submit it with a final button.
What would be the best way of doing this?
window.firstViewModel = new function()
{
var self = this;
self.firstProperty = ko.observable();
//
}
window.secondViewModel = new function()
{
var self = this;
self.secondProperty = ko.observable();
//
}
var submit = function()
{
var firstProperty = firstViewModel.firstProperty(); // access to firstViewModel
var secondProperty = secondViewModel.secondProperty(); // access to secondViewModel
//...
}
I would recommend going towards a Single Page Application.
Essentially, you would have a single view model with sections for each step in the wizard, and on submit, you have all the data you need.
The visibility/aesthetics can be controlled via css and intelligent binding.
RP Niemeyer has a good demo, and also talks about it in this answer.