I'm using BBB with the great LayoutManager for the views.
Unfortunately, i can't find a way to re-render specific subviews. Here is my setting:
Home.Views.Layout = Backbone.Layout.extend({
template: "home/home",
el: "#main",
views: {
"#left-menu-container": new Home.Views.Leftmenu(),
"#searchbox": new Home.Views.Searchbox(),
"#content": new Home.Views.Content()
}
});
Home.HomeView = new Home.Views.Layout();
Home.HomeView.render();
Home.Views.AddEditPatient = Backbone.View.extend({
template: "......",
events: {
'click .dosomething': 'dosomething'
},
dosomething: function(){
// [dosomething]
// Only Render Sub-View, e.g. #content here...
}
});
I don't want to re-render the whole layout, what would be possible by calling Home.HomeView.render() again, but how can i render only the sub-view in this setting?
I think you want to add to do something like this with backbone.layoutmanager
thisLayout.setView("#content", new View()).render();
The backbone.layoutmanager v0.6.6 documentation might be helpful
http://documentup.com/tbranyen/backbone.layoutmanager/#usage/nested-views
Also check
http://vimeo.com/32765088
If I understand your question correctly, you can do this in your dosomething function:
this.$("#divToRenderTo").html(new subView().render().$el);
Be sure to have "return this;" at the end of your sub-view's render function.
There are two ways I generally do this with layoutmanager:
Instantiate views in your initialize function and then drop them into the view in beforeRender. This gives your view access to the subview so you can render it directly.
initialize: function() {
this.subview = new SubView();
},
beforeRender: function() {
this.insertView(this.subview);
},
doSomething: function() {
this.subview.render();
}
You can use view.getView(#selector) to return the embedded view and then call render on that.
doSomething: function() {
this.getView('#content').render();
}
Related
I'm attempting to create a reusable typeahead component(?) for my app. I'm using twitter's typeahead javascript library and trying to create a custom component/view out of it.
I would like to be able to define the typeahead in my templates like so:
{{view App.TypeAhead name=ta_name1 prefretch=prefetch1 template=template1 valueHolder=ta_value1}}
I was thinking those variables would be located in the controllers:
App.ApplicationController = Ember.Controller.extend({
ta_name1: 'movies',
prefetch1: '../js/stubs/post_1960.json',
template1: '<p><strong>{{value}}</strong> - {{year}}</p>',
ta_value1: null
});
I don't know what i need to use to accomplish this, a component or a view. I would imagine it would something like this.
App.Typeahead = Ember.View.extend({
templateName: 'typeahead',
didInsertElement: function() {
$('.typeahead').typeahead([{
name: this.getName(),
prefetch: this.getPrefetch(),
template: this.getTemplate(),
engine: Hogan,
limit: 10
}]);
$('.typeahead').on('typeahead:selected', function(datum) {
this.set('controllers.current.' + this.getValueHolder()), datum);
});
}
});
With a template like
<script type="text/x-handlebars" data-template-name='typeahead'>
<input class="typeahead" type="text">
</script>
I don't know how to get away from the jQuery class selector. In reality, i will have more than one typeahead on a form so this class selection isn't going to cut it.
I also don't know how to get the values from the controller in the View. Obviously the getPrefetch(), getTemplate(), getValueHolder(), etc methods don't exist.
I know this is a TON of pseudo code but hopefully i can get pointed in the right direction.
You probably want to use a component for this.
The secret afterwards is that Ember components (and View) expose a this.$ function which is a jQuery selector scoped to the current view. So you only need to do this:
didInsertElement: function() {
this.$(".typeahead"); // ... etc
}
Take a look at my Twitter TypeAhead implementation for Ember.
you can use it like this:
APP.CardiologistsTypeAhead = Bootstrap.Forms.TypeAhead.extend({
dataset_limit: 10,
dataset_valueKey: 'id',
dataset_engine: Bootstrap.TypeAhead.HandlebarsEngine.create(),
dataset_template: '<strong>{{lastName}} {{firstName}}</strong>',
dataset_remote: {
url: '%QUERY',
override: function (query, done) {
$.connection.cardiologists.server.getAllByLastNameLike(query) //SignalR
.then(function (cariologists) {
done(cariologists);
});
}
},
didInsertElement: function () {
this._super();
var self = this;
Em.run.schedule('actions', this, function () {
var cardiologistFullName = this.get('controller.content.cardiologistFullName');
self.get('childViews')[1].$().val(cardiologistFullName);
});
},
valueChanged: function () {
this._super();
this.get('childViews')[1].$().typeahead('setQuery', this.get('controller.content.cardiologistFullName'));
}.observes('value'),
selected: function (cardiologist) {
var cardiologistFullName = '%# %#'.fmt(Em.get(cardiologist, 'lastName'), Em.get(cardiologist, 'firstName'));
this.set('controller.content.cardiologistFullName', cardiologistFullName);
this.set('value', Em.get(cardiologist, 'id'));
}
});
and the handlebars:
{{view APP.CardiologistsTypeAhead
classNames="col-sm-6"
label="Cardiologist:"
valueBinding="controller.content.referrerCardiologist"}}
Hello here is my little code :
i don't know how to make this more marionette ... the save function is too much like backbone...
self.model.save(null, {
success: function(){
self.render();
var vFormSuccess = new VFormSuccess();
this.$(".return").html(vFormSuccess.render().$el);
}
var VFormSuccess = Marionette.ItemView.extend({
template: "#form-success"
} );
http://jsfiddle.net/Yazpj/724/
I would be using events to show your success view, as well as using a layout to show your success view, if it's going into a different location.
MyLayout = Marionette.Layout.extend({
template: "#layout-template",
regions: {
form: ".form",
notification: ".return"
}
initialize: function () {
this.listenTo(this.model,'sync',this.showSuccess);
this.form.show(new FormView({model: this.model}));
},
showSuccess: function () {
this.notification.show(new VFormSuccess());
}
});
Or, you could do the same with just the one region, and having the FormView be the layout itself. You just need to ensure there is an element matching the notification region exists in the layout-template.
MyLayout = Marionette.Layout.extend({
template: "#layout-template",
regions: {
notification: ".return"
}
initialize: function () {
this.listenTo(this.model,'sync',this.showSuccess);
},
showSuccess: function () {
this.notification.show(new VFormSuccess());
}
});
What this allows you to do:
You can then show an error view quite easily, if you wanted. You could replace initialize with
initialize: function () {
this.listenTo(this.model,'sync',this.showSuccess);
this.listenTo(this.model,'error',this.showError);
},
and then add the following, ensuring you create a VFormError view.
showError: function () {
this.notification.show(new VFormError());
}
You should be able to write
self.model.save(null, {
success: function(){
self.render();
}
...
Why are you doing this
this.$(".return").html(vFormSuccess.render().$el);
If you define that template as the view template you could simply refer to it with $el, if you need two different templates then you might think about using a Controller, to decide what to use and who to use it.
If you use Marionette, you don't call render directly but instead use Marionette.Region to show your views.
Okay so I have a parent view which has a click event which renders a child view. Within this child view is a form which I'm trying to validate and then submit. So my parent view looks something like this:
var MapView = Backbone.View.extend({
el: '.body',
template: _.template(MapTemplate),
render: function() {
...
},
events: {
'click #log-pane-title': 'loadLogView'
},
loadLogView: function() {
var eventLogView = new EventLogView({
id: properties._id
});
eventLogView.render();
}
});
And my child view looks something like this:
var EventLogView = Backbone.View.extend({
el: '#eventlog',
logform: new NewLogForm({
template: _.template(AddLogTemplate),
model: new LogModel()
}).render(),
render: function() {
// Render the form
$("#addtolog").html(this.logform.el);
},
events: {
'submit #addlogentry': 'test'
},
test: function() {
alert('inside eventlogview');
return false;
}
});
The problem I'm facing is that test() never fires. For debugging purposes I made sure the submit event was even firing by putting:
$('#addlogentry').on('submit', function() {
alert( "submit firing" );
return false;
});
In render() of the EventLogView. That does actually trigger, so I'm not sure what's going on and why test() isn't triggering.
To avoid scoping issues all the events delegation are scoped to the views el in Backbone.
So your #addlogentry button should live inside your EventLogView el.
And your sanity check in the render should look something like this to mimic how Backbone works internally :
this.$el.on('submit', '#addlogentry', function() {
alert( "submit firing" );
return false;
});
I am probably missing something easy or doing something wrong, but I am trying this and can't get it to fire the function...
var Home = Backbone.View.extend({
indexAction: function() {
console.log('index');
},
render: function() {
console.log('render');
}
});
Home.indexAction();
All I get is this error:
Uncaught TypeError: Object function (){return i.apply(this,arguments)}
has no method 'indexAction'
You created the view type but did not create an instance.
You need to instantiate a view of type Home now:
var h = new Home();
h.indexAction();
Also, it might be better to rename Home as HomeView, so you know it's a view which can be instantiated.
var HomeView = Backbone.View.extend({
indexAction: function() {
console.log('index');
},
render: function() {
console.log('render');
}
});
var home = new HomeView();
example on backbone docs
I was looking to this example Introduction to Backbone.js Part 2.
In this example the render function is called when I click on button:
events: {
"click button": "render"
},
How can I call the render function when the model is loaded?
var view = new View({ model: model });
You need just to add the following line this.render(); to your initialize function in your View Class
initialize: function()
{
this.template = $('#list-template').children();
this.render();
},