In one of the rails app I am trying to use backbone with "rails-backbone" gem,
And I have created one model using scaffolding which is working fine.
but I have another model and I am trying to use different router for it, but when tries to instantiate that router from index.html.erb it fires,
"Uncaught TypeError: undefined is not a function" which clearly means there is no such router. But it is there and even in developer's tool it shows those JS files. I tried all different ways but it didn't work. Thanks in advance.
I'd guess that you're defining your router like this:
class SomeRouter extends Backbone.Router
# router code goes here
and then you're trying to create one with:
r = new SomeRouter
But CoffeeScript will wrap your files in a function to prevent scope creep:
Although suppressed within this documentation for clarity, all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.
If you'd like to create top-level variables for other scripts to use, attach them as properties on window, or on the exports object in CommonJS. The existential operator (covered below), gives you a reliable way to figure out where to add them; if you're targeting both CommonJS and the browser: exports ? this
That wrapper will hide SomeRouter inside a function so there will be no SomeRouter visible outside the file which defines it.
A common solution in Rails/Backbone apps is to manage the namespaces yourself. Set up your own namespace somewhere before any other (Java|Coffee)Script will be pulled in:
# AppName is just a placeholder, you'd use something more
# sensible in real life.
window.AppName =
Routers: { }
Views: { }
Models: { }
Collections: { }
and then define your router as:
class AppName.Routers.SomeRouter extends Backbone.Router
#...
and later:
r = new AppName.Routers.SomeRouter
similarly with models, collections, and views that need to be globally visible.
Related
My TypeScript and plain JavaScript code need to share a namespace and some data. TypeScript should "prepare" a namespace, external JS provides data, TypeScript processes it.
The context is an Angular 2 application. The loading order is:
Angular 2 app with its JavaScript starts
a custom external JavaScript file is dynamically loaded from an external source (JSONP style)
Angular 2 app does further processing on the data generated by the loaded JS file
Currently in the external JavaScript file I'm doing something like this:
if (typeof Blog === 'undefined')
{
Blog = {
Posts: []
}
}
// ...
Blog.Posts.push(post);
In my Angular 2 app this JavaScript file is being dynamically loaded and the value then accessed like this:
declare var Blog: any;
...
let firstPost = Blog.Posts[0];
This works, I can access data placed by the external JS.
Now I want to keep the JavaScript part as minimal as possible. So I want to move the declaration of Blog and Posts to TypeScript, preferably so that it can be used there in a strongly typed fashion.
So I wish my JavaScript looked like this:
// ...
Blog.Posts.push(post);
Note the missing declaration of Blog. I tried something like this in TypeScript:
declare var Blog: BlogClass; // <- this is probably wrong, can be changed to anything necessary to make it work...
// ...
Blog = new BlogClass();
But apparently its not that easy. My Angular 2 app dies on me with a generic error message. The error is caused by Blog = new BlogClass().
Any hints on how to solve this?
declare means that the thing being declared must be defined somewhere else.
declare var Blog: BlogClass;
does not produce any code in the resulting javascript, so this assignment
Blog = new BlogClass();
fails at runtime because Blog does not exist.
When you remove declare, this line appears in the generated code:
var Blog;
However, it does not necessarily create var Blog in global scope - when you compile typescript code as modules, it will be created inside a module and will be inaccessible to external javascript code, unless you go through the route of exporting it from typescript module and importing that module in your javacsript code.
The simplest (but a bit dirty) way to make sure that an object is created in global scope is to do that explicitly:
(window as any).Blog = new BlogClass();
I've recently started to use RequireJS, which enables me to organize my code in a nice way. So, define and require became my best friends. But now I see one problem, which I do not know how to solve in terms of RequireJS, or in terms of some particular Design Pattern. So, imagine, I have a really huge module containing zillions of methods. I define it like so:
define(function(BIG_MODULE){
return {
property_0: "value_0",
property_1: "value_1",
....
property_zillion: "value_zillion",
method_0: function(){...},
...
method_zillion: function(){...}
}
});
Please, do not ask me, why I have such a huge module - it's just an abstraction. And, so, the question now is - if it is possible to import or require not the entire module, but some of its properties and methods? Lets say I somehow assigned my module to some local instance and if I investigate the internals of this instance, then I can see, that it contains only some particular properties and methods. Is it possible?
One thing you definitely should do is not export anything that is not meant to be part of the public API of your module.
This being said, RequireJS has no notion of importing only part of a module. When you list a module as a dependency, RequireJS loads the module, loads and executes its dependencies, calls its factory function (this is the function passed to define) with the resolved dependencies, and records what the module exported. Then when you use it somewhere else, the module's export value is bound to the corresponding parameter in the callback. So in this code
require(["foo"], function (foo) {...
you get as foo all of what was exported by the module "foo".
If you use ES6 (aka ES2015) and have the ES6 modules converted to AMD modules (by Babel, for instance), then you can have some language-based notion of a partial import. For instance, if foo exports like this return { bar: 1, baz: 2, bwip: 3 } then you could import only bar like this:
import { bar } from "foo";
console.log(bar);
This would output 1 to the console. Note, however, that this does not change how the module is loaded and processed by RequireJS. RequireJS reads the whole module and executes all of the factory function. The import above only affects how the code that loads "foo" gets to access the exported values.
I am mildly familiar with require.js and Backbone.js having used them together for about a year now and relatively new to Backbone.Marionette although I am very interested in what it can bring to the table.
In looking for examples of project structure (I can get a little obsessed with this stuff) I have found https://github.com/BoilerplateMVC/Marionette-Require-Boilerplate and other similar examples.
Something that has been bothering me: in their app.js file, they return a reference to an instance of a Marionette application, ie:
var app = new Backbone.Marionette.Application();
app.addInitializer(...);
...
return app;
And in many components, they reference the app.js via require.js and use as follows:
define([..., 'app'], function (... , App) {
App.someProperty(...);
});
Now here's what I'm not understanding: I have been under the assumption that the code in their app.js is really more like a Factory than a Class since it returns an instance of an application rather than, say, a modified prototype or extension thereof.
Therefore, when they reference app.js, aren't they actually creating a whole new instance rather than accessing some sort of shared instance? There is nothing to suggest that app.js is returning a singleton in their code.
And yet, it works, and obviously I am the one who is confused.
So, why does this work?
This works because objects are passed by reference in javascript and the fact that require.js only loads every dependency once. Then, app.js returns an initialized instance, and every other module that requires 'app' gets reference to the same object.
It's not a factory, it's simply an initialized application object instance.
My application has a View() model that fetches HTML, CSS, etc. with a simple call to a view path. As many of these views and viewlets are shared or required multiple times I'd like to maintain a 'cache' object of loaded views that any new instance of a View() can check and read from if that particular view has been loaded.
In a requireJS implementation, any ideas on where is best to put this view 'cache' object? Ideally I'd like to have something like a Session() object that contains it, and I'd be able to reference a single instance of Session() from anywhere in my app.
Any thoughts on best practices for this?
Many thanks!
I suggest you to use a Singleton approach creating a simple module for this case. For instance, you could create a module like this:
define(["mydep","myotherdep"], function(dep1,dep2){
var Hellovariable = {
"attr1": ...,
"attr2": ...,
...
"attrN": ...
}
return Hellovariable;
});
When you call this module using AMD you will only have an unique instance for this variable and its attributes.
I'm building a dashboard application with Backbone.js
There is a grid of panes called modules. Each module has its own custom data that it needs to listen to.
In this sense, I have created a backbone model called Module that is basically the top-level information for each module like module_name & module_description
my first inclination is to find a way to make a new special module model per module... like a "counter" module, a "messages" module, etc.
how should I approach the separate & different data per module? any design pattern recommendations?
You can do something like this:
var Module = Backbone.Model.extend({
// default properties/methods of this module
});
var MessageModule = Module.extend({
// new properties/methods of this module
});