I'm trying to implement breadcrumb using Backbone with Marionette's Module.
My idea is, to the UL tag add the LI tag one by one.
In my HTML I have a UL tag with id 'Breadcrumb'.
I created breadcrumb Module as below:
App.module("BreadcrumbModule", function(BreadcrumbModule){
var Breadcrumb = Backbone.Model.extend({
defaults:{
name : '',
link : ''
}
});
var BreadcrumbList = Backbone.Collection.extend({
model : Breadcrumb
});
var BreadcrumbView = Backbone.View.extend({
tagName : 'li',
render : function() {
$(this.el).html('' + this.model.get('name') + '');
return this;
}
});
var BreadcrumbListView = Backbone.View.extend({
el : '#Breadcrumb',
initialize : function() {
_.bindAll(this, 'render', 'appendBreadcrumb');
this.collection = new BreadcrumbList();
this.collection.bind('add', this.appendBreadcrumb);
},
render:function(){
$.each(this.collection.models, function(i, breadcrumb){
self.appendBreadcrumb(breadcrumb);
});
},
appendBreadcrumb: function(breadcrumb) {
var breadcrumbView = new BreadcrumbView({
model : breadcrumb
});
// THIS IS NOT WORKING!
$(this.el).append(breadcrumbView.render().el);
}
});
// Public function
BreadcrumbModule.getBreadcrumbListView = function(){
return new BreadcrumbListView();
}
BreadcrumbModule.getBreadcrumb = function(breadcrumb){
return new Breadcrumb(breadcrumb);
}
});
Tried to access in the same module:
breadcrumbListView = new BreadcrumbListView();
breadcrumb = new Breadcrumb({name : 'Home',link : 'home'});
breadcrumbView = new BreadcrumbView({model:breadcrumb});
breadcrumbListView.collection.add(breadcrumb);
In another module I'm adding an item to the breadcurmb as follows:
this.breadcrumbListView = App.BreadcrumbModule.getBreadcrumbListView();
breadcrumb = App.BreadcrumbModule.getBreadcrumb({link: 'home', name: 'Home'});
this.breadcrumbListView.collection.add(breadcrumb);
In both of the cases it is not working. I checked the LI tag is generated properly.
But it is not adding the value to the BreadcrumbListView's el '#Breadcrumb'.
in the function appendBreadcrumb() if I give as follows also its not working, but from the firebug it is working.
$('#Breadcrumb').html('ADD SOME TEXT');
But my main container $('#contentContainer') have scope and we can set value to it.
contentContainer -> in the HTML.
Breadcrumb -> in the template file.
That means from the view I cannot set value to an id coming from a template file.
Note: I'm not using RequireJS.
How can I fix this issue?
Thank you!
//San.
Related
I'm working on backbone website that uses disqus as its commenting system, I use backbone boilerplate, and I registered a module for the comment, I included in it the js provided by DISQUS
my module looks like this :
define([
'namespace',
'use!backbone'
], function(namespace, Backbone) {
var Comment = namespace.module();
Comment.Views.CommentView = Backbone.View.extend({
template: "app/tpl/comment/main.html",
render: function(done) {
var view = this;
namespace.fetchTemplate(this.template, function(tmpl) {
view.el.innerHTML = tmpl();
if (_.isFunction(done)) {
done(view.el);
}
});
},
commentScript: function() {
console.log('Comment Script INIT.');
var disqus_identifier = 'a unique identifier for each page where Disqus is present';
var disqus_title = 'a unique title for each page where Disqus is present';
var disqus_url = 'a unique URL for each page where Disqus is present';
var disqus_developer = 1;
var disqus_shortname = 'dandin95'; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
}
});
return Comment;
});
my main.html only contain a div with id 'disqus_thread' that used view the comment box
My issue is : when rendering my view nothing done and chrome console shows
Uncaught TypeError: Cannot call method 'toLowerCase' of null embed.js:65
when adding this script to the template every thing working well.
Any advice ????
Basically, it looks like you are creating a backbone view to initialize and render the DISQUS widget within the #disqus_thread DIV and then re-render based on the state of the page:
define('disqus', [], function(){
var disqus_shortname = DISQUS_SHORTNAME,
disqus_identifer = INDEX_IDENT,
disqus_title = DISCOVERY_TITLE,
disqus_url = URL_HERE,
disqus_developer = '1'; // could be deprecated?
var DisqusView = Backbone.View.extend({
el: '#disqus_thread',
initialize: function() {
// DISQUS universal code:
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
},
render: function(options) {
DISQUS.reset({
options: options,
reload: true,
config: function(){
this.page.identifer = options.identifer;
this.page.title = options.title;
}
});
}
});
var disqusView = new DisqusView();
return disqusView;
});
OK! so lets make the assumption that the #disqus_thread element already exists on the page (hence setting el). When the module is loaded, DISQUS will do the initialization.
Say an event is fired off that requires the loading of a new Disqus thread:
$('.article_title').on('click', function(e) {
var $post = $(e.target).attr('id');
disqus.render({
identifier: $post, // OR however you decide to determine these attributes
title: $post
});
});
The iFrame within the #disqus_thread element will then be reloaded to the proper thread. This is a very thinly layered example, but imagine calling disqus.render({...}) within an events hash or router.
DISQUS Ajax Reset Snippet
Edited This Below
In this image below I have two main regions.
One for the user list on the left: allusersRegion
And another for the the right side where a layout is displayed, which contains unique attributes to the user that was clicked in the allusersRegion and a list of articles by the user: middleCoreRegion
**If you noticed the middleCoreRegion is showing all articles by all users..This is wrong and I am trying to show all articles of the individual user (in this case. "kev")
I tried to see if my problem was with my JSON api (served via node/rest/mongoose) or with my underscore templates, but if it displays both list then I suppose I need to filter from inside backbone.
At first I tried using a Marionette.vent to simply change the url, but somhow I can't get the _id name into the url: function(), it says undefined...
var someuser = this.model.get("_id");
myApp.vent.trigger("showarticles", someuser);
I add a listener in the backbone collection on the same page:
myApp.vent.on("showarticles", someuser);
**The Edit (A Different Way of Doing this) Here is my code
var usertab = Poplive.module('usertab', {
startWithParent: true,
});
usertab.addInitializer(function() {
User = Backbone.Model.extend({});
UniqueArticle = Backbone.Model.extend({});
//Collections
Users = Backbone.Collection.extend({
model: User,
url: '/api/user2'
});
UniqueArticles = Backbone.Collection.extend({
model: UniqueArticle,
url: '/api/survey'
});
//Layout
var VisitingLayoutView = Backbone.Marionette.Layout.extend({
template: "#visiting-layout",
regions: {
firstRegion: "#listone",
secondRegion: "#listtwo",
thirdRegion: "#listthree",
playRegion: "#playhere",
articlesRegion: "#articleshere"
}
});
AllUserView = Backbone.Marionette.ItemView.extend({
template: "#tab-alluser-template",
tagName: 'li',
events: {
"click #openprofile" : "OpenProfile"
},
OpenProfile: function(){
console.log("Profile is open for " + this.model.get("username"));
var modelo = this.model.get("_id");
var vlv = new VisitingLayoutView({model: this.model});
Poplive.middleCoreRegion.show(vlv);
var ua = new UniqueArticles();
var uacoll = new UniqueArticlesView({collection: ua});
vlv.articlesRegion.show(uacoll);
}
})
//ItemViews
UniqueArticleView = Backbone.Marionette.ItemView.extend({
template: "#unique-article-template"
});
//CollectionViews
AllUsersView = Backbone.Marionette.CompositeView.extend({
template: "#tab-allusers-template",
itemView: AllUserView
});
UniqueArticlesView = Backbone.Marionette.CollectionView.extend({
template: "#unique-articles-template",
itemView: UniqueArticleView
});
//Render Views
var alluserview = new AllUserView();
var allusersview = new AllUsersView();
//Fetch Collections
var theusers = new Users();
theusers.fetch();
var userscoll = new AllUsersView({collection: theusers});
Poplive.allusersRegion.show(userscoll);
});
Assuming UniqueArticle to be the Backbone Model, for the Model with a specific id to be fetched you would need to define the urlRoot property which will append the id of the model to the request.
So the id attribute will be appended to the end of the request the model from the server when you do a fetch on it
var UniqueArticle = Backbone.Model.extend({
idAttribute : 'someuser',
urlRoot : function(someuser){
return '/api/visitingarticles/'
}
// this would send a request for
// /api/visitingarticles/someId
});
var UniqueArticles = Backbone.Collection.extend({
model: Article,
url : function(someuser){
return '/api/visitingarticles/'
}
// /api/visitingarticles -- All Articles will be fetched
});
I think what you want, is to define url as a function, and have a user attribute on your collection:
var UniqueArticles = Backbone.Collection.extend({
model: Article,
initialize: function(){
var self = this;
myApp.vent.on("showarticles", function(someuser){
self.user = someuser;
self.fetch();
}
},
url : function(){
var fragment = '/api/visitingarticles/';
if(this.user && this.user.id){
return fragment + this.user.id;
}
return fragment;
}
});
(Disclaimer: untested code, but it works in my head :D)
Then each time you trigger the event, the userattribute is updated, the collection is reset with the updated url.
As a side note, you might want to look into using a filtered collection. I've implemented that idea in my book, based on Derick Bailey's code here: http://jsfiddle.net/derickbailey/7tvzF/
Here is my version: https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/entities/common.js
And an example of its use (lines 38-41): https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/apps/contacts/list/list_controller.js#L38
I've started learning Backbone.js and tried to write my first app with Collections. Here is the code:
console.clear();
(function($){
window.App = {
Models : {},
Collections : {},
Views : {}
};
//a single estimate
App.Models.Estimate = Backbone.Model.extend({});
// multiple esitmates
App.Collections.Estimates = Backbone.Collection.extend({
model : App.Collections.Estimate
});
App.Views.Estimates = Backbone.View.extend({
tagName: 'ul',
render : function(){
this.collection.each(this.addTo,this);
},
addTo:function(estimate){
var dir = App.Views.Estimate({model:estimate}).render();
this.$el.append(dir.el);
}
});
App.Views.Estimate = Backbone.View.extend({
tagName: 'li',
render :function(){
this.$el.html(this.model.get('title'));
return this;
}
});
var jSon = [{title:'Abhiram', estimate:8}];
var estimates = new App.Collections.Estimates(jSon);
console.log(estimates);
var tasksView = new App.Views.Estimates({collection:estimates});
// var a = tasksView.render().el;
//console.log(a);
})($j||jQuery);
I've all the three included :
jQuery first, Underscore next and Backbone. I keep getting "Undefined is not a function".Please let me know if i am doing anything wrong.
Thanks!
Are you sure that you want to assign collection App.Collections.Estimate as model to it self?
// multiple esitmates
App.Collections.Estimates = Backbone.Collection.extend({
model : App.Collections.Estimate
});
I've got a simple div into which I'd like backbone to render a select box and options from my server.
The options seem to render just fine, but the select box does not. I'm sure it's a simple tweak, but can't seem to find it.
I created a simplified fiddle for it: http://jsfiddle.net/thunderrabbit/BNZY3/
The HTML
<div id="where_fields"></div>
The script I'm using uses fetch() to get the data. The Fiddle above hardcodes the data, but the issue is the same.
(function($){
var Field = Backbone.Model.extend();
var UnitFields = Backbone.Collection.extend({
url: '/<?php echo CONFIG_ADMIN_DIR; ?>/api/fieldnames/units',
model: Field
});
var BuildingFields = Backbone.Collection.extend({
url: '/<?php echo CONFIG_ADMIN_DIR; ?>/api/fieldnames/buildings',
model: Field
});
var FieldView = Backbone.View.extend({
tagName: "option",
initialize: function(){
_.bindAll(this, 'render');
},
events: {
"click":"clicked"
},
clicked: function(e) {
var data_type = this.model.get("DATA_TYPE");
if(data_type == "varchar") {
console.log("it's a varchar");
}
if(data_type == "int") {
console.log("it's an int");
}
},
render: function(){
$(this.el).attr('value', this.model.get('COLUMN_NAME')).html(this.model.get('display_name'));
return this;
}
});
var FieldsView = Backbone.View.extend({
tagName: "select",
el: $('#where_fields'),
initialize: function(){
_.bindAll(this, 'render', 'renderItem');
this.collection.bind('reset', this.render);
},
renderItem: function(model) {
console.log('rendr item');
var fieldView = new FieldView({model:model});
fieldView.render();
$(this.el).append(fieldView.el);
},
render: function(){
console.log('rendr');
this.collection.each(this.renderItem);
return this;
}
});
var units_fields = new UnitFields();
var buildings_fields = new BuildingFields();
var unitsView = new FieldsView({collection: units_fields});
var buildingsView = new FieldsView({collection: buildings_fields});
units_fields.fetch();
buildings_fields.fetch();
})(jQuery);
Why is my backbone script not rendering the select tags?
You have both tagName and el attributes in your FieldsView class. You don't need both. Use tagName if you want to render a view detached from the DOM and then backbone will use that tag instead of the default of div. However, in your render(), you don't ever actually get a select tag involved. $(this.el) is your #where_fields div and you just append fieldView.el, which is an option element. That's why there is no select element. Some quick tips:
use this.$el as a more efficient shorthand for $(this.el)
It's preferable to keep your view loosely coupled from the DOM, so el: $('#where_fields') is not as clean a design as rendering an element detached from the DOM and letting other code decide where exactly in the existing DOM it should be attached.
So you should remove your el properly, set tagName to select if you like, then your render() method will be doing what you want with is appending options to a select tag, then move the actual code to append your view's rendered el to the #where_fields div out of the view into your router perhaps.
I am stuck with setting jCarousel jquery plugin inside Backbone Marionette application. With pure Backbone I found a solution using onShow function.
But this does not work in Marionette
Here is the code of Marionette:
$(document).ready(function(){
MyApp = new Backbone.Marionette.Application();
MyApp.addRegions({
TagsRegion: "#mycarousel"
});
MyApp.Tag = Backbone.Model.extend({
});
MyApp.TagCollection = Backbone.Collection.extend({
model: MyApp.Tag,
url: 'json/photos.json'
});
MyApp.TagItemView = Backbone.Marionette.ItemView.extend({
template: "#tag-template",
tagName: 'li'
});
MyApp.TagCollectionView = Backbone.Marionette.CollectionView.extend({
itemView: MyApp.TagItemView,
tagName: 'ul'
});
MyApp.addInitializer(function(options){
var tagCollection = new MyApp.TagCollection();
var tagCollectionView = new MyApp.TagCollectionView({
collection: tagCollection
});
tagCollection.fetch();
MyApp.TagsRegion.show(tagCollectionView);
});
MyApp.start();
});//END jQUERY
</script>
Then I am trying to find a solution how to build in the plugin...
var PluginView = Backbone.View.extend({
el:$('#mycarousel'),
onShow: function(){
this.$el.jcarousel({
scroll: 1,
auto: 13,
wrap: "circular",
size: 5,
initCallback: function mycarousel_initCallback(carousel) {
$('.jcarousel-control a').bind('click', function () {
carousel.scroll($.jcarousel.intval($(this).text()));
return false;
});
},
itemVisibleInCallback: {
onAfterAnimation: function (c, o, i, s) {
i = (i - 1) % $('#mycarousel li').size();
$('.jcarousel-control a').removeClass('active').addClass('inactive');
$('.jcarousel-control a:eq(' + i + ')').removeClass('inactive').addClass('active');
}
}
}); //jcarousel end
} //onShow function end
}); //PluginView End
var plug_view = new PluginView();
plug_view.render();
if (plug_view.onShow){
plug_view.onShow();
};
The problem is that carousel is based on UL with a bunch of li-tags and both the plugin and the marionette generates their own li-tags simultaneously. As a result a have empty carousel-li-tags and marionette-generated-li-tags containing all images and other content to be used inside carousel-li-tags.
I would appreciate if anyone helps to find any solution for this case as well as jquery-plugins in marionette in general.
If you use the Marionette ItemView, there is an onShow method that is fired once the view is rendered to the DOM. Then you would:
MyApp.TagsRegion.show(ItemViewGoesHere);
this will render your item view and once the content is rendered to the DOM, your onShow method will be called and you can render your jQuery plugin to an element within the view.