Backbone.js - Binding from one view to another? - view

I have a main app view, with a filter menu in the header. When it's clicked, I want to filter content in a seperate news-feed view. But I don't know how to bind events (and pass class data) from clicks in one view to a function in another.
How can I accomplish this?

There are a number of ways to accomplish this, but probably you want to create a model object, which is shared between the two views. Then on 'click' in view one, update the model object, and bind 'on change' in view two to the model object.
Basically, you can set up both views to stay in sync with the model object, and any changes to the object will result in changes to the view.

Everything in Backbone inherits from Backbone.Events, so you can trigger and bind events from anywhere (docs for Backbone.Events):
var View1 = Backbone.View.extend();
var View2 = Backbone.View.extend({
eventHandler: function(data) {alert(data)}
});
var v1 = new View1;
var v2 = new View2;
v1.bind('hello-world-event', v2.eventHandler)
v1.trigger('hello-world-event', 'Hello World!')
Note that in this example, when v2.eventHandler is called, 'this' will refer to v1. See the backbone docs for more.

Related

Backbone routing and view relations

I'm preparing to build a medium sized website with Backbone for the first time. There are 7 menu items, and I cant figure out whats the best routing/view relationship when it comes to performance. When a route is triggered, do I create a new instance of the "active" view every time it's triggered or do I only create one view instance for each view, when the user loads the page?
... And whats the best way to handle views – adding and removing dom elements and events, without having trouble with performance. e.g.
$('selector').html(my-new-view);
You can create your menu only once, if it doesnt change. You can create some html template like this.
<div>
<nav>render-here-only-one</nav>
<section>render-here-when-page-changes/loads</section>
</div>
I prefer backbone's render method initialize and append itself.
var testView = Backbone.View.extend({
el: $("#section"),
template:_.template("<strong>hello.</strong>")
initialize: function () {
// any change on view will trigger render
_.bindAll(this, "render");
},
render: function (item) {
this.el.html(this.template());
}
});
var myView = new testView();
myView.render();

Does nativescript use 2 view models

In the image of this project which is the view model file? I would have thought main-page.js but then main-view-model.js is titled "-view-model".
"view-model file" is not really a set programming concept. But I guess you mean a file which only holds one function which acts as a view-model. If that's the case, then main-view-model.js is most probably the "view-model file". Looking at the content it looks view-model-ish.
However 1, you need to look at main-page.js to see how that is used.
However 2, in NativeScript, view models are often observable objects and looking at this code, the ViewModelItem is not an observable object.
not sure about that ViewModelItem object, but in NativeScript, view1.xml is the view and view1.js would be the "code-behind" and that means you will code the logic directly related to the view itself: Button has a tap="getName"? that function goes to view1.js...
viewModel files would be where you create observables with the datas you fetch from a remote source for exemple, and all the methods say 'saveName(ppl)' that would POST your object to the server would be in the viewModel file...
you would create your observable like this:
var studentList = new StudentListViewModel([]);
var pageData = observableModule.fromObject({
studentList: studentList,
student: "",
prof: "Choisir"
});
and any changes has to be set like that:
pageData.set("prof", prof)
hope it is clear...

Manually load kendo mobile view

I'm working on a Kendo Mobile project with a number of:
Kendo Views (external to root html)
Modal Views (in the root html).
The external files load on demand and everything works fine. But i'd like to have the same load on demand behavior for some of the modal views, because the root/based html file is becoming too large and not manageable.
Is there a way to either:
Store a modal view in an external file? If so is it possible to load via javascript syntax (app.navigate()) rather than the declarative syntax (href='externalmodal').
Manually pre-load an external view without navigating to it first.
This code lets you manually create a view:
var viewUrl = 'blahblahblah';
var element = $.parseHTML('<div data-role=view>test</div>')[0];
element.style.display = 'none';
$(document.body).append(element);
var options = $.extend({}, kendo.parseOptions(element, kendo.mobile.ui.View.fn.options));
var view = new kendo.mobile.ui.View(element, options);
view.element[0].setAttribute('data-url', viewUrl);
kendo.mobile.application.navigate(viewUrl, '');
Depending on what features you use, you may need to instead use code similar that that used for ModalView below so that Kendo creates the subclass (changes: substitute View for ModalView, substitute view for modalview, add data-url, remove call to show(), maybe check that view not already created by checking for element with matching data-url). We haven't tested setting roles.view this way, but we did something similar while testing this stuff out and it worked.
Don't try settings the options - Kendo got confused (at least trying to set useNativeScrolling didn't work, also don't try setting the options object on the subclass unless you really know what you are doing).
Caveat: This was using browserHistory:false (which disables routing) when the kendo.mobile.Application was created. The technique should still work when using browser history if you use a valid url fragment (same as would be created by Kendo for the pushstate/hashchange url).
This is a also way to cleanly subclass kendo.mobile.ui.View that works well - although you must still use data-role=view even though your subclass is a "different" component. Note that you can't just use you cant use your own subclassed component with its own name like role=myview to subclass a view because there are hard-coded checks specifically for data-role=view in the kendo codebase. Same if you wish to subclass: layout modalview drawer splitview page (amongst other hard-coded kendo ui component names - search kendo code for kendo.roleSelector - ugly). e.g.
MyView = kendo.mobile.ui.View.extend({
init: function(element, options) {
kendo.mobile.ui.View.prototype.init.apply(this, arguments);
...
var myView = new MyView('<div data-role=view>test</div>');
Why it works: The relevant function in the Kendo source code is _findViewElement which does element = this.container.children("[" + attr("url") + "='" + urlPath + "']"); to see if the view already exists for a url, before creating a new one. A unique init function is always required as it ends up being the constructor function.
If you want to subclass a modalview, you need to do something different due to the way kendo works:
var MyModalView = kendo.mobile.ui.ModalView.extend({
html: '<div data-role=modalview style="width:90%;display:none;">Foobar</div>',
init: function() {
kendo.mobile.ui.ModalView.prototype.init.apply(this, arguments);
}
});
function makeModalView() {
$(document.body).append($.parseHTML(MyModalView.prototype.html));
var roles = $.extend({}, kendo.mobile.ui.roles);
roles.modalview = MyModalView;
var modalView = kendo.initWidget($(element), {}, roles);
modalView.open();
return modalView;
}

Is it ok to use App.__container__.lookup to access instances?

I need access to the ApplicationView from another view and I'm able to do so with App.__container__.lookup('view:application').
Is __container__ intended to be used this way?
Is there a better way to access instances of views?
(update)
My usecase:
My ApplicationView has a template with 2 columns.
The CSS is responsive so the size of the columns changes to accommodate the
width of the page.
I'm using Ember List View which requires height and width to be specified during initialization
I want to get the instance so I can access the DOM object to figure out its size
I can't use Ember.View.views because at that point, the ApplicationView has not been inserted into the DOM
Don't use that. One of the core developers said that whenever someone tries to use App.__container__, he would add another underscore.
If you really want to access an Ember.View intance use Ember.View.views['foo']. Where foo is the elementId of the view instance.
So if for example you want the App.ApplicationView instance:
App.ApplicationView = Ember.View.extend({
elementId: 'application'
});
// somewhere else in your code
var applicationViewInstance = Ember.View.views['application'];
Having said that, I never came across a situation where I needed to access view instances like that. If you can post your use case, I may be able to suggest alternative ways.
UPDATE: You want to access some properties of a view instance, from some other view instance (view height and width). You can pass those properties to the controller and let other controllers access them for using them in other views (source view -> source controller -> some other controller -> some other view):
App.ApplicationView = Ember.View.extend({
didInsertElement: function() {
var controller = this.get('controller'),
height = this.$().height(),
width = this.$().width();
controller.setProperties({
height: height,
width: width
});
}
});
App.SomeotherController = Ember.Controller.extend({
needs: ['application'],
applicationViewWidthBinding: 'controllers.application.width',
applicationViewHeightBinding: 'controllers.application.height'
});
App.SomeOtherView = Ember.View.extend({
// assuming its controller is an instance of App.SomeotherController
applicationViewWidthBinding: 'controller.applicationViewWidth',
applicationViewHeightBinding: 'controller.applicationViewHeight'
});

Backbone JS where to put Application main logic

Using Backbone i'm starting to build an App where i have everything cleanly separated. But now i have the following question. Where should i put the App main logic, in the views or in the model.
For example i have a view and a model, which are binded to a button and when i click that button i have to make
$.ajax(params)
do i put that in the view or the view calls a method with :
this.model.doAction(params)
which do you think is the best approach?
You can define an events property in the view which is of the format {"event selector": "callback"} for eg. {"click .collapse": "collapse"} where collapse would be a function defined as a property of the view. Then write your ajax request code in this callback function.
Also, unless I am missing something, "binding a view and model to a button" doesn't sound correct Backbone way to me. Instead you should think of one instance of model associated with one instance of the view. Whenever an attribute of the the model instance changes, a model change event will be triggered. You can bind a view function to this event so that change in the model is reflected in the view. Here is a quick example
var Book = Backbone.Model.extend({
// ...
});
var BookView = Backbone.View.extend({
initialize: function () {
this.model.bind('change', this.render, this);
},
render: function () {
// here, make changes to the dom as per changes in model
}
});
To associate a model with a view instance, you can pass the it while instantiating a new
view object..
var book = new Book({
title: "A great book"
});
var view = new BookView({model: book});
view.model.set('author', 'AGreatAuthor');
The set function call will fire change event and will result in render function of view
to be called.
Refer to the annotated source of Todos app example for a complete example.

Resources