BackboneJS + RequireJS How to add external JS-Plugins - backbone.js

I want to implement this external JS-plugin, https://github.com/GBKS/Wookmark-jQuery, into my Backbone App. My issue is that I use RequireJS and I really dont know how to get it running. I already asked this before BackboneJS + Require JS + Wookmark.js plugin not working but adding it to my App.js doesnt work at all. So does anyone know what might be the issue here?
The wookmark + imagesloaded plugins both appear in my console, so they get loaded. I tried to run it from a View with no success.
Please help...

Since wookmark depends on jquery, I would recommend adding it to requirejs shim:
require.config({
paths: {
jquery: 'path/to/jquery'
wookmark: 'path/to/wookmark'
},
shim: {
wookmark: { deps: [ 'jquery' ] }
}
});
Hope it will solve your problem.

Related

textAngular.js with requireJS gives saveSelection error after change

Does anyone able to get textAngular.js with RequireJS(even if someone has working example I will replicate the settings)?
I am able to load editor but when applying h1 tags I get
$window.rangy.saveSelection is not a function on textAngular.js file with _savedSelection = $window.rangy.saveSelection();
Here are versions I am using.
Angular 1.4.8
textAngular 1.4.6
Rangy 1.3.1-dev
RequireJS 2.1.22
The issue is textAngular in its core, expects a variable rangy to be available globally (https://github.com/aaronroberson/textAngular/blob/master/src/main.js#L69).
So to fix this problem, we combined the rangy-core and rangy-selectionsaverestore into our window.rangy at the beginning of the bootstrap of our application before we initialise the app with angular.module('appname', [modules...])
define(["angular", "ngRoute", "jquery", "rangy-core", "rangy-selectionsaverestore"], function(angular, ngRoute, $j, rangyCore, rangySelectionSavereStore) {
window.rangy = $j.extend(rangyCore, rangySelectionSavereStore);
});
Configuration for requirejs to load these two modules,
'rangy-core': '../bower_components/rangy/rangy-core',
'rangy-selectionsaverestore': '../bower_components/rangy/rangy-selectionsaverestore'

AngularJS and gulp - getting less errors than I think I should in the console

I'm building a site. First I made myself familiar with AngularJS in general and tried to make sense of all the new things for me: grunt, livereload, angularjs... I soon realized some mistakes I made and started building a new project from the ground up.
When I was building the site whilst on the grunt server. It displayed me more messages than it is now with gulp. I'm not sure why is that?
For example, since I was moving some existing code from my "study-project" to a new clean-start-gulp-project. I forgot to add one service: FlashService - responsible for displaying simple messages on my site.
And I was already using that as a dependency in another service. But for some reason all I was presented was a blank site with no messages in the console. Whereas in my previous project I always got messages like "No such provider found" or something similar. Can anybody help me make debuging easier?
Some other things have changed also. I changed the general folder structure of the code and I'm trying to modularize my new app. Currently I can't think of anything else that might even be remotely related.
My current folder structure is like this:
src/app
app.js
/services
auth-service.js
flash-service.js
Some important parts from my code:
app.js
angular.module('myapp', [
...
'myapp.home'
]).config(function ($stateProvider) {
$stateProvider.state('main', {
'abstract': true,
resolve: {
promiseUser: ['AuthService', function (AuthService) { AuthService.promiseUser; }]
},
template: '<div ui-view></div>'
});
})
AuthService
angular.module('myapp').service('AuthService', ['FlashService', function (FlashService){
// As soon as I created the missing service 'FlashService' everything started working.
// Or when I simply removed the FlashService from dependencies.
// What I don't understand is why didn't I get any errors in the console?
}
Since I already spent too much time looking the bug in a wrong place I can only imagine that some other messages might also not make it into the console. This would eventually make debuging quite hard.
What am I missing here? Why didn't I get any errors in the console?
Edit:
The first project was generated using Yeoman and for the second one I used gulp slush. Don't think this will help, but I figured might be worth mentioning.
Edit2
Found out that if I change angular.js and add console.log(message) inside the first minError function, I almost get what I want.
function minErr(module) {
...
console.log(message);
return new Error(message);
}
Now I just need to figure out an alternative way to do this or what was different with yeoman generated application and why I am not getting these messages by default:
[$injector:unpr] Unknown provider: aProvider <- a <- AuthService
http://errors.angularjs.org/1.2.25/$injector/unpr?p0=aProvider%20%3C-%20a%20%3C-%20AuthService
Loading modules with Angular if you want error messages always try and catch. My guess that gulp slush is not generating a try/catch scenario for loading modules while yeoman does. The difference between gulp and grunt shouldn't matter so long as you are trying to catch the error. The thing with gulp is that it is all process based some of something failed in the process sometimes the process will just sit there or just stop all together.
Disclaimer: I have never generated a project with slush only yeoman.
Okay, so I'll try to explain what I figured out.
This had nothing to do with gulp nor grunt. Also the directory structure was completely irrelevant.
First, let's take a look at some of the most important parts of both config files.
current:
angular.module('myapp', [])
.config(function ($stateProvider) {
$stateProvider.state('main', {
'abstract': true,
resolve: {
promiseUser: ['AuthService', function (AuthService) { AuthService.promiseUser; }]
},
template: '<div ui-view></div>'
});
})
...
before:
angular.module('myapp', [])
.config(function ($stateProvider) {
$stateProvider.state('main', {
'abstract': true,
resolve: {
promiseUser: ['AuthService', function (AuthService) { AuthService.promiseUser; }]
},
template: '<div ui-view></div>'
});
})
...
.run(['AuthService', function (AuthService) { ... }]);
...
So the first part is the same in both cases. What was different before is that I also used AuthService inside a run block.
I was checking that on state change the authenticated user had permissions to access the new state.
So what happened inside the resolve stayed inside the resolve! But what happened inside the run block was displayed in the console.
By modifying these parts of the code - both projects displayed the same errors and had the same behavior.

unit testing angular directives templateUrl (include requirejs and ng-html2js

I am working on a not-yet-huge angular app. I have got a problem with karma unit testing. To make a long story short, I am using angular with requirej. My tests run well if I keep my template embedded in my directive. But as this app will be huge, it will not scale. But when I move the template and load it in my directive with templateUrl, I can not get rid of one of the following errors (depending on how I modify the conf):
(initial error) "Unexpected request: GET path/to/mytpl.html"
"ReferenceError: Can't find variable: angular". This error occurs with different config:
when I put {pattern: 'path/to/mytpl.html', included: false} in my karma.conf and add a requirejs's define path/to/mytpl.html in my test file (this is the way I would like that to work).
when I put path/to/mytpl.html in my karma.conf then all my template return this error (whether I am using ng-html2-js preprocessor or not).
"Error: [$injector:modulerr] Failed to instantiate module templates due to:
Error: [$injector:nomod] Module 'templates' is not available!". I saw that karma-ng-html2js-preprocessor could be use to create a module that will contains all templates, but it never worked.
NB: I do not use FQN in karma.conf, I use it here to be consistent. I do not think that matters, but I prefer to precise it
I saw someone putting each 'path/to/mytpl.html': {deps: ['angular']} in the shim section of their test-main.js. But it does not work for me and that solution will not scale.
I had the same problem and found solution in the following article.
I guess your problem is in wrong karma or requireJS config, in particular base path setup.
In case your directive templateUrl is relative and that url can't be resolved correctly against karma base path or requireJS base path, then you need to work out this issue.
Let's assume your directive has 'app/directive/myDirective.html' value for templateUrl. Then:
Check if your html file is properly included into files section of karma config, pay attention to included:false setting:
files: [
//...
{ pattern: 'path_to_directive/myDirective.html', included: false },
//...
],
of course you can use a wild card chars like * or **, but for troubleshooting purposes I would start with a full path value. According to the value of basePath in karma config, 'path_to_directive' will or won't be the same as path in your app.
Ex: if karma base path is one level up from you app root, then your 'path_to_directive' = 'some-folder/app/directive/myDirective.html'
Make sure you can get your file from the browser. Go to http://localhost:karma_port/base/path_to_directive/myDirective.html.js
While doing this test pay attention to:
base prefix in the url (karma serves all files from that virtual path and adds this prefix to all urls)
'.js' at the end of your url
Once you get file in step 2, you'll see the actual module code, created by html2js preprocessor. It should look something like this:
angular.module('module_path/myDirective.html', []).run(function($templateCache) {
$templateCache.put('module_path/myDirective.html',
//...
Make sure module_path is 'app/directive/'. If not then you have 2 options:
module_path has some prefix => simply remove it by adding the following to karma config:
ngHtml2JsPreprocessor: { stripPrefix: 'modulePrefix' }
module_path is shorter => add missing part:
ngHtml2JsPreprocessor: { prependPrefix: 'missingPart' }
Restart karma and make sure 'module_path' in step 3 is 'app/directive/'
Make sure you have added angular dependency for your template module (check test-main.js which is basically config file for requireJS). Also keep in mind, that value in shim section will be resolved according to baseUrl value in your test-main.js file. For simplicity, I'll assume that requireJS can get the file from 'requirejs_path/myDirective.html' path.
shim: {
//..
'requirejs_path/myDirective.html': { deps: ['angular'] },
//..
}
Make sure you have included your template as a dependency to your test and also don't forget to load the module:
define(['requirejs_path/myDirective.html', 'angular-mocks', '...'], function () {
describe('test suite', function() {
//...
beforeEach(module('app/directive/myDirective.html'));
//...
});
});
I hope by completing these 6 step you'll get a working test. Good luck.
After having set aside this problem for a while and use this time to improve my knowledge and to widen my app, I found a solution.
Brief methodology recap: as karma-ng-html2js-preprocessor or karma-html2js-preprocessor seems to work on some other projects and as they are referenced in the official doc, I tried many (almost all, I think) possible configuration combinations to run one of them in my test environment. With no success, I came the clue : I have to drop them and find another way.
The solution came from grunt-html2js. By simply adding to grunt configuration the basic set-up and run grunt, it generate a module containing all my templates - maybe, I will split it later in more meaningful modules. But from here, work is almost done. Then I just had to :
tell karma to serve the file has other external tools file: [ {pattern: 'path/to/mytplmodule.js', included: false}, ...]
register the path in my require conf for tests path: [ 'templates' : 'path/to/mytplmodule', ...]
shim it, still in require conf for tests, to be sure it won't be loaded before angular shim: [ 'templates' : 'angular', ...]
load this module in my test file define(['templates',...], function(){...});
retrieve the tested directive's template beforeEach(module('path/to/mytpl.html'));
add a step in your grunt configuration to make it automatically generated before running tests.
That's all !
There is a drawback with this approach, it requires to retrieve or mock all other directives' templates used in the tested directive. It could be boring as number of directives grows. But I prefer that for now as it is not invasive for the application's code. Maybe later, especially when I will include javascript's compilation in my process, I will move it from test to app too.

Require.js & Marionette: defining includes when extending classes

I'm working on a project using Require.js, Backbone and Marionette, and the define/function calls at the top of my files are getting a bit ludicrous. I'd like to find a way to move the "includes" out of the topmost define block, and into the extend where the are relevant.
So my structure roughly looks like this:
define(['underscore','jquery','handlebars','someTemplate','someModel',etc...], function(_,$,Handlebars,template,model,etc...){
var someView = Backbone.Marionette.ItemView.extend({
// code here
});
return someView;
});
So as I add more views to the file, that define list gets really, really, long. I've tried doing something like:
var someView = define(['someTemplate','someModel'], function(template, model){
return Backbone.Marionette.ItemView.extend({
// code here
});
]);
But then someView is undefined when I call it later. Am I doing this wrong, or is it not possible?
You should split your modules. Having a really long list of dependencies is a sign that your module does to much. Most of the time all view need is model or collection and maybe some subViews and the global eventbus.
Also think about the need to require jQuery,Backbone etc. This are stuff that you will need in most of your modules, its easier to combine them in one file and load them in the first place. There is no much advantage to require this files, all it does is cluttering your define section with a lot of boilerplate.
The define call btw. does not return anything thats why someView is undefined in example. If you really wanna go with this solution you have to use require when you use someView later on. But even then its much cleaner to put someView in its own module file.
you can use your require.js config file dependencies shim to aggregate your "common" or needed
modules into one namespace:
shim: {
marionette: {
deps: ["backbone", "json2", "bootstrap", "backboneRpc"],
exports: 'Marionette'
},
flot_pie: {
deps: ['jquery', 'charting', 'flot_resize'],
exports: '$.plot'
},
}
so now you can call all you need like this:
define([
'marionette',
'flot_pie'
],
function(Marionette, graph) {

Backbone-localstorage doesn't work with require.js

I'm trying to add localstorage to my collections in backbone.js, but for some reason, require.js wont load it.
Here's what is in the main.js file that requirejs loads:
require.config({
paths: {
'jquery': 'libs/jquery/jquery-1.7.1.min',
'underscore': 'libs/underscore/underscore-min',
'backbone': 'libs/backbone/backbone-min',
'backbone-localstorage': 'libs/backbone-localstorage/backbone-localstorage-min',
'text': 'libs/require/text'
}
});
You can see the full source at https://github.com/tominated/Vendotron. I can tell it's not loading because when I put the localstorage snippet into my collection, it errors out in chrome's console saying that Store isn't defined.
Any idea what I'm doing wrong?
As Paul said, you are not requiring the localstorage module anywhere. Require.js 2.0 has a specific mechanism for JavaScript code that is essentially a plugin for other code - the shim option. Including localStorage would look like this:
require.config({
baseUrl: "/js/",
paths: {
jquery: 'lib/jquery-1.8.0',
underscore: 'lib/underscore-1.3.3',
backbone: 'lib/backbone-0.9.2',
'backbone.localStorage': 'lib/backbone.localStorage'
},
shim: {
underscore: {
exports: "_"
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'backbone.localStorage': {
deps: ['backbone'],
exports: 'Backbone'
}
}
});
This example was copied from the article "Build Backbone Apps Using RequireJS" which also explains how to structure your code and how to compile the code into one file when deploying the application.
There are a couple problems.
First, you are setting the path to backbone-localstorage, but you are never requiring it anywhere, so it is never actually loaded. Setting that path is basically defining a shortcut to it, not loading it.
The second problem is that, like backbone itself, most backbone plugins are not AMD modules. They want to have Backbone loaded first, so they can add their extensions to it.
It looks like you are using an AMD fork of Backbone, but not backbone-localstorage. You could try to find an existing one, or make your own similar to this.
Either that, or you can try to load backbone-localstorage as-is (adding to the dependencies list of your define call), but you would need to use the !order plugin to make sure backbone is loaded first.
On looking inside the source code, where underscore and backbone are required, your path definition in require config should tally with the required path in local storage I.e case sensitive

Resources