Backbone-localstorage doesn't work with require.js - backbone.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

Related

AngularJS libraries conflicting with each other

I'm using gulp to combine my scripts in order to load only one file in HTML (make it faster).
Here's a sample code, name of libraries don't matter much, you'll get the idea :
// gulpfile.js
mix.scripts([
'vendor/jquery-2.1.1.min.js',
'vendor/angular.js',
'vendor/slideout.min.js',
'vendor/dirPaginate.js',
'vendor/cookie.js'
], 'public/js/libs.js');
And then I do this :
// app.js
let app = angular.module('app', ['angular-slideout', 'cookie', 'dir-paginate'], function ($interpolateProvider) {
$interpolateProvider.startSymbol('<%');
$interpolateProvider.endSymbol('%>');
});
export default app;
I only use one file to load every NG library in my project, and then I import this app in my controllers. Now this is only an example, but I already have conflicts depending on the order of mixing these scripts in.
Any advice on processing this ? I already had to ditch some libs I wanted to use because they were conflicting with others. Going on this way, this looks like a dead end.

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.

BackboneJS + RequireJS How to add external JS-Plugins

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.

require.js load the same files, do not depending what I put to main.js

I have main.js file which looks like this
require.config({
paths: {
'angular': '../../dist/js/libs/angular/angular'
,'file1': 'libs/folder1/file1'
,'file2': 'libs/folder2/file2'
,'file3': 'libs/folder3/file3'
,'async': 'libs/requirejs/2.1.1/async'
,'domReady': 'libs/requirejs/2.1.1/domReady'
},
shim: {}});
I need to add angular-backbone script to project, trying to add in path something like 'angboot': './libs/angular-bootstrap/ui-bootstrap-tpls' but it dosen't work, it's still not presented in the header after page loaded. Also I comment some other files like file1 or file2, but when I reload the page they still in header. I press ctrl+f5, clear cache - but result still the same.
What I doing wrong?
require.config only tells RequireJS where to find modules should it need them. It doesn't actually load modules until they're required. Usually, that will either happen as a dependency with require:
require(['file1', 'file2' /* ... */], function(file1, file2) {
/* ... */
});
…or as a dependency of one of those modules (and of those, and so on).

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) {

Resources