Here is my basic backbone view for changing routes. I would like to get the href attribute of the clicked link. How to do that? Here is a code bellow:
var Menu = Backbone.View.extend({
el: '.nav',
events: {
'click a' : 'changeRoute'
},
changeRoute: function(e) {
e.preventDefault();
//var href = $(this).attr("href");
router.navigate(href, true);
}
});
I am a newbie in backbone, so please have mercy :)
you can use: var element = $(e.currentTarget);
then any attributes can be called like this: element.attr('id')
so in your code above:
changeRoute: function(e) {
e.preventDefault();
var href = $(e.currentTarget).attr("href");
router.navigate(href, true);
}
Related
I'd gone through most of the solution for this issue but still couldn't solve it. Please help me guys. T.T
My child event is not firing no matter how I configure it please guide me through it.
My parent is 'dayInfo' and I'm calling 'schedule' from the parent.
But the html button is not triggering the event.
///// schedule.html /////
<a class="ic-plus-circle add"></a>
///// schedule.js /////
define(function(require) {
var Backbone = require('backbone'),
User = require('models/User'),
css = require('text!views/dayInfo/schedule.css'),
tpl = require('text!views/dayInfo/schedule.html');
return Backbone.View.extend({
initialize: function(options) {
this.template = _.template(tpl);
var self = this;
return this;
},
render: function() {
var self = this;
self.$el.html(self.template());
return this;
},
events: {
'tap .add': function(e) {
console.log('success');
var self = this;
var $this = $(e.currentTarget);
console.log('tapped');
}
}
});
});
////// dayInfo.html /////
<div class="tab-content"></div>
////// dayInfo.js /////
define(function(require) {
var Backbone = require('backbone'),
ScheduleView = require('views/dayInfo/schedule'),
css = require('text!views/dayInfo/dayInfo.css'),
tpl = require('text!views/dayInfo/dayInfo.html');
return Backbone.View.extend({
id : 'dayInfo',
initialize: function(options) {
this.template = _.template(tpl);
var self = this;
return this;
},
render: function() {
var self = this;
self.$el.html(self.template());
self.$tabContent = self.$el.find('.tab-content');
self.scheduleView = new ScheduleView({date:self.date,doctor:self.doctor,appointments:self.appointments,events:self.events}).render();
self.$tabContent.html(self.scheduleView.$el);
}
});
});
I was expecting the console to throw 'tapped' whenever I click the button
There is no such thing as tap event, which is why it's not firing. See MDN - Touch events for list of available touch events.
You'll need to get a touch event plugin what works with jQuery to have custom events such as tap
I have an Backbone App where I fetch different collections by clicking a Letter from a list. So, I want to add a Progressbar or some kind of rotating image but I dont know how to do this.
My View looks like this
function (App, Backbone) {
var Artists = App.module();
var ArtistView = Backbone.View.extend({
tagName : 'li',
template: 'artistItem',
serialize: function() {
var data = this.model.toJSON();
data.letter = this.model.collection.letter;
return data;
},
});
Artists.View = Backbone.View.extend({
tagName : 'ul',
className : 'artistList',
initialize: function() {
this.listenTo(this.collection, 'all', this.render);
this.listenTo(App, 'navigateLetter', this.updateState);
},
beforeRender: function() {
var self = this;
this.collection.each(function(item) {
self.insertView(new ArtistView({model: item}))
})
},
updateState: function(letter) {
this.collection.letter = letter;
this.stopListening(this.collection);
this.collection.fetch();
this.listenTo(this.collection, 'all', this.render);
}
});
Artists.ArtistsCollection = Backbone.Collection.extend({
url: function() {
return '/projects/mdk/index.php/api/artists/' + this.letter;
}
});
return Artists;
});
So does anyone have an idea how to do this? I could imagine I should do something in initialize or beforeRender?
Thanks in advance
You can use a spinner for the loading effect. For that you need
spin.js
Add entry of that spin.js into main file.
To use that spinner.
var yourSpinner = new Spinner();
var target = document.getElementById('spinHere');
yourSpinner.spin(target);
e.g in your case take updateState:function(){} :
updateState: function(letter) {
this.collection.letter = letter;
this.stopListening(this.collection);
var yourSpinner = new Spinner();
var target = document.getElementById('spinHere');
yourSpinner.spin(target);
this.collection.fetch();
yourSpinner.stop();
this.listenTo(this.collection, 'all', this.render);
}
Take a look at this: https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/apps/contacts/list/list_controller.js#L4
It's from my Marionette book app, where the idea is to immediately display a loading view, and when the collection is fetched, render the actual view (and closing the loading view, which is Handled by Marionette). It would give something like (pseudocode):
var loadingView = new ContactManager.Common.Views.Loading();
ContactManager.mainRegion.show(loadingView);
var fetchingContacts = myCollection.fetch();
$.when(fetchingContacts).done(function(contacts){
ContactManager.mainRegion.show(new MyCollView({ collection: contacts }));
});
The code uses a deferred to determine when the collection has been fetched (and therefore the new view should be displayed). You can learn more about using deferreds here:
http://davidsulc.com/blog/2013/04/01/using-jquery-promises-to-render-backbone-views-after-fetching-data/
http://davidsulc.com/blog/2013/04/02/rendering-a-view-after-multiple-async-functions-return-using-promises/
I have a pretty simple mainmenu with 4 anchors and the relevant views to them. Anyhow, on one of those views I want to add a little submenu with 3 tabs, which after clicking them they show a different view. I figured out how to do it with pushState:false but what I want is a clean URL. Right now, my URL would look like http://localhost/myproject/#secondpage/subview1 or http://localhost/myproject/#secondpage/subview2 etc etc. So does anyone know how I do achieve http://localhost/secondpage no matter which subview/tab is triggered?
Im using RequireJS and HandlebarsJS (for HTML-templating)
So right now my code (snippets) look like this:
Router.js
routes: {
'': 'index',
'firstpage' : 'firstpage',
'secondpage' : 'secondpage',
'secondpage/sub1' : 'sub1',
'secondpage/sub2' : 'sub2',
'secondpage/sub3' : 'sub3',
'thirdpage' : 'thirdpage'
},
Backbone.history.start({
pushState: false
});
My HTML with the anchors:
<ul>
<li>
<a class="sub1" href="#secondpage/sub1">Bands</a>
</li>
<li>
<a class="sub2" href="#secondpage/sub2">Koncert</a>
</li>
<li>
<a class="sub3" href="#secondpage/sub3">Locations</a>
</li>
</ul>
and my View looks like
define(['backbone','handlebars', 'text!templates/SubMenu.html'],
function(Backbone,Handlebars, Template) {
'use strict';
var SubMenuView = Backbone.View.extend({
template: Handlebars.compile(Template),
initialize: function () {
_.bindAll(this);
},
render: function() {
$(this.el).html(this.template());
return this;
}
});
return SubMenuView;
}
);
Another thing is: should I move the actions to the View by setting events? I kind of tried that but it didnt work since the Views are defined in the router...
What I tried is to set pushState:true, then I removed the secondpage/sub1 thingies in my router, then in my View I wrote:
events: {
'click a.sub1': 'sub1',
},
sub1: function(event) {
event.preventDefault();
var sub1Router = new Backbone.Router();
var route = '/secondpage/';
sub1Router.navigate(route, {trigger: true});
},
but that didnt work, that gave me URL not found so...
Any help is welcome! Thanks in advance...
[UPDATE]
OK, so by request, here is my (new) router:
var Router = Backbone.Router.extend({
routes: {
'': 'index',
'firstpage' : 'firstpage',
'secondpage' : 'secondpage',
'thirdpage' : 'thirdpage'
},
initialize: function () {
var self = this;
//Views
this.mainMenuView = new MainMenuView({el:'#mainMenu'}).render();
this.subMenuView = new SubMenuView();
Backbone.history.start({
pushState: true
});
},
index: function () {
var self = this;
},
firstpage: function() {
this.firstpageView = new FirstpageView({el:'#topContent'}).render();
},
secondpage: function() {
this.secondpageView = new SecondpageView({el:'#topContent'}).render();
this.subMenuView = new SubMenuView({el:'#subMenu'}).render();
},
thirdpage: function() {
var thirdpageView = new ThirdpageView({ el:'#topContent', collection:this.categoryCollection}).render();
},
sub1: function() {
this.sub1View = new Sub1View({el:'#subContent_2'}).render();
},
sub2: function() {
this.sub2View = new Sub2View({el:'#subContent_2'}).render();
},
sub3: function() {
this.sub3View = new Sub3View({el:'#subContent_2'}).render();
}
});
return Router;
}
And my (new) View looks like:
var SubMenuView = Backbone.View.extend({
template: Handlebars.compile(Template),
events: {
'click .sub1': 'sub1',
'click .sub2': 'sub2',
'click .sub3': 'sub3',
},
sub1: function(event) {
var sub1Router = new Backbone.Router();
var route = '/secondpage';
sub1Router.navigate(route, {trigger: true});
},
sub2: function(event) {
event.preventDefault();
var sub2Router = new Backbone.Router();
var route = '/secondpage';
sub2Router.navigate(route, {trigger: true});
},
sub3: function(event) {
event.preventDefault();
var sub3Router = new Backbone.Router();
var route = '/secondpage';
sub3Router.navigate(route, {trigger: true});
},
initialize: function () {
_.bindAll(this);
},
render: function() {
$(this.el).html(this.template());
return this;
}
});
return SubMenuView;
And my (new) HTML template:
<ul>
<li>
<a class="sub1" href="/secondpage/">Sub1</a>
</li>
<li>
<a class="sub2" href="/secondpage/">Sub2</a>
</li>
<li>
<a class="sub3" href="/secondpage/">Sub3</a>
</li>
</ul>
Hope this can contribute to more input/suggestions... This is really driving me nuts which make me consider using .show() and .hide() jquery method even if i dont really want...
What you're describing is how backbone routing works, either you use '/secondpage/sub1' and use server routes, or use '#secondpage/sub1' and hit backbone routing. Either way the address bar is going to update with your URL.
One alternative option is to use a events inside the view, handling a click event and updating the view's template accordingly.
However, if you're intent on using routes then maybe have a look at clickify.js. I haven't used it myself yet, although I have it bookmarked for potential future use... sounds like it might do what you want.
try to use this in your router :
Backbone.history.navigate('secondpage');
after all the work is done (the models are fetched the views are rendered)
I have the problem that the event "form:selectedForm" is calling the method "showForm" but when sending this to my view I am getting the following error: TypeError: e[t] is not a function.
This is stated in line 128 in the backbone.js script but I have no clue what he is doing there. It looks like that he is looking for a "to" or "on" event on the collection.
What I am doing wrong here?
MyController = Backbone.Marionette.Controller.extend({
initialize: function(options) {
this.options = options;
this.urls = options.urls;
this.mainRegion = options.mainRegion;
this.view = new MyLayout();
this.mainRegion.show(this.view);
this.view.render();
this.showSelectorView(this.view.formHeader);
},
showSelectorView : function(view) {
var forms = new MyForms();
forms = this.urls.loadForms;
var selectorView = new FormSelectorView({
collection: forms
});
forms.fetch();
this.listenTo(selectorView, "form:selectedForm", this.showForm);
view.show(selectorView);
},
showForm : function(models) {
console.log("showForm");
var form = new FormContentView({
collection: models
});
this.view.form.show(form);
}
});
MyLayout = Backbone.Marionette.Layout.extend({
template: Backbone.Marionette.TemplateCache.get('#content'),
regions: {
formHeader: "#selector",
form: "#formContent",
formContent: "#content",
formFooter: "#save",
formTemplates: "#templates"
}
});
FormSelectorView = Backbone.Marionette.ItemView.extend({
template: Backbone.Marionette.TemplateCache.get('form-selector-template'),
events : {
"click option" : "selectForm"
},
initialize : function() {
this.listenTo(this.collection, "sync", this.render, this);
},
selectForm : function(e) {
e.preventDefault();
var id = $(e.currentTarget).attr("name");
var item = this.collection.get(id);
this.trigger("form:selectedForm", item.attributes.fields);
}
});
I think the error is in your showSelector view function, you are overwriting your forms collection in the second line,
i think your intention in that line was to assing the url of the forms collection so my guess is that this will fix it:
showSelectorView : function(view) {
var forms = new MyForms();
forms.url = this.urls.loadForms; /// Im assuming you were trying to pass the url here
var selectorView = new FormSelectorView({
collection: forms
});
forms.fetch();
this.listenTo(selectorView, "form:selectedForm", this.showForm);
view.show(selectorView);
},
I have a small backbone class:
view = Backbone.View.extend({
events: {
"click textarea" : "doSomething"
},
doSomething : function() {
var textarea = $(this.el).find('textarea')
// I would like to just call, this.textarea, or this.elements.textarea
}
});
Ideally I would like to be able to access my textarea through a variable instead of having to search the element every time. Anyone have any idea on how to accomplish this?
maybe i am under thinking it but how bout giving the textarea a class or id and target specifically when needed,
or create a sub view that generates the textarea
var View = Backbone.View.extend({
el: '#main',
initialize: function(){
this.render();
},
render: function() {
var subview = new SubView();
this.$('form').append(subview.el);
this.$('form').show();
},
});
var SubView = Backbone.View.extend({
tagName: 'textarea',
id: 'whateverId',
events: {
"click" : "doSomething"
},
initialize: function(){
this.render();
},
doSomething : function(event) {
var textarea = $(event.target);
// or var textarea = $(this.el);
},
render: function(){
return $(this.el);
}
});
The other answers get you the reference that you need, but if you really need a handle to the textarea, then you can do something like this:
view = Backbone.View.extend({
initialize: function() {
this.myTextareaElement = $(this.el).find('textarea')
}
events: {
"click textarea" : "doSomething"
},
doSomething : function() {
// use this.myTextareaElement ...
}
});
pass the event as the argument and then use the event target
view = Backbone.View.extend({
events: {
"click textarea" : "doSomething"
},
doSomething : function(event) {
var textarea = $(event.target);
}
});