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
Related
I am fairly new to Protractor and Page Objects. I am trying to get the header to show across multiple pages. I have a header_page.js and a header_spec.js. I can verify that the header is present once within the header_spec.js (which is presently only pointing to the home page). What I would like to do is call the test for the header each time I visit a page.
var HomePage = require('../pages/home_page.js');
var HeaderPage = require('../pages/header_page.js');
describe('When visiting a page'. function(){
var headerPage = new HeaderPage();
var inbox_page = new HomePage();
beforeEach(function () {
inbox_page.visit();
});
it('header menu selector should be present', function(){
header_menu = headerPage.hdr_menu;
header_menu.click();
expect('header_menu').not.toBe(null);
});
});
});
I am not sure how to call this test from page2_spec.js..page3_spec.js as each page is different but should all contain a header. I am trying to avoid code duplication and would like to avoid calling the "it" block from each page. Do I use a helper file or can I move the it block inside the header_page.js..currently looks like this:
module.exports = function(){
this.hdr_menu = element(by.css('#pick-group-btn'));
this.hdr_img = element(by.css('PeopleAdmin logo'));
}
you can call a test spec to other specs by wrapping your spec in a function and exporting it "requiring" that module So in your case you can export header_spec.js to other modules such as page2_spec.js or page3_spec.js by :
var HomePage = require('../pages/home_page.js');
var HeaderPage = require('../pages/header_page.js');
var commHeader = function(){
describe('When visiting a page'. function(){
var headerPage = new HeaderPage();
var inbox_page = new HomePage();
beforeEach(function () {
inbox_page.visit();
});
it('header menu selector should be present', function(){
header_menu = headerPage.hdr_menu;
header_menu.click();
expect('header_menu').not.toBe(null);
});
});
});
}
module.exports = commHeader;
Then in you page2_spec.js file you can import this module like this :
var commHeader = require('your path to spec/commHeader.js');
describe('When visiting page 2 validate Header first'. function(){
var headerTest = new commHeader();
headerTest.commHeader();
it('page 2 element validations', function(){
//here the page 2 test goes
});
});
});
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.
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
Yes I am new to JS and also in backbonejs.
Lets dig into the problem now.
I am having a very strange behaviour of this in backbonejs Controller.
Here is the code of my controller
var controller = Backbone.Controller.extend( {
_index: null,
routes: {
"": "index"
},
initialize: function(options){
var self = this;
if (this._index === null){
$.getJSON('data/album1.json',function(data) {
//this line is working self._index is being set
self._index = new sphinx.views.IndexView({model: self._photos});
});
Backbone.history.loadUrl();
}
},
index: function() {
//this line is not working
//here THIS is pointing to a different object
//rather than it was available through THIS in initialize method
this._index.render();
}
});
Here is the lines at the end of the file to initiate controller.
removeFallbacks();
gallery = new controller;
Backbone.history.start();
Now , i am missing something. But what ???
If this is the wrong way what is the right way??
I need to access the properties i set from the initialize method from index method.
It looks like the caller function of index method is changing it's scope.
I need to preserve the scope of that.
You have to specify the route action into a Backbone Route not into a Controller. Inside the router is where you are going to initialize your controller and views.
Also, there is no method Backbone.history.loadURL(). I think you should use instead Backbone.history.start() and then call the navigate in the router instance e.g. router.navigate('state or URL');
var myApp = Backbone.Router.extend( {
_index: null,
routes: {
"": "index"
},
initialize: function(options){
//Initialize your app here
this.myApp = new myApp();
//Initialize your views here
this.myAppViews = new myAppView(/* args */);
var self = this;
if (this._index === null){
$.getJSON('data/album1.json',function(data) {
//this line is working self._index is being set
self._index = new sphinx.views.IndexView({model: self._photos});
});
Backbone.history.loadUrl(); //Change this to Backbone.history.start();
}
},
// Route actions
index: function() {
this._index.render();
}
});
I have these routes in my webservice and I can hit either of them directly through the browser and I return the correct value.
app.get('/repairs', repair.findAll);
app.get('/repairs/:id', repair.findById);
When I ask Backbone to do this I am unexpectedly getting a call to
app.get('/repairs', repair.findAll);
when I expect it to reach
app.get('/repairs/:id', repair.findById);
The piece of code that appears to be calling "/repairs" rather than "/repairs/:id" is
var EditRepair = Backbone.View.extend({
el : '.page',
render : function(options) {
var scope = this;
var repair = new Repair({id: options.id});
//This has the correct id
console.log(options.id);
//I would expect this to call /repairs/12344312
//However it calls /repairs
repair.fetch({
success : function(repair){
var template = _.template($('#edit-repair-template').html(), {repair : repair});
scope.$el.html(template);
}
});
}
});
var Repair = Backbone.Model.extend({
urlRoot : 'repairs'
});
var Router = Backbone.Router.extend({
routes: {
'edit/:id' : 'editRepair'
}
});
var editRepair = new EditRepair();
var router = new Router();
router.on('route:editRepair', function(id) {
console.log('Edit Id : ' + id);
editRepair.render({id:id});
});
The options.id can be console.logged and shows the correct id of the item. I've had a few issues so far with the difference between _id in mongodb and id in backbone which I have worked around but for the life of me I cannot see why this is issuing a call to repairs and not repairs/id.
Any help appreciated.
My fault, I had an ajax prefilter that was encoding the uri components.
This was messing up the requests being issued.
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.url = "http://localhost:3000/" + encodeURIComponent( options.url );
console.log(options.url);
});
Changed to
$.ajaxPrefilter( function( options, originalOptions, jqXHR ) {
options.url = "http://localhost:3000/" + options.url;
console.log(options.url);
});