I am using steve sanderson's yeoman knockout scaffolding described here.
However I have one issue which is if I decide to create folders for different types of modules, and If I then want to inject one of these modules into my components using folder name conventions then I have to use a very verbose path resolution like "../../services/service".
define(["knockout", "text!./home.html","../../services/service"], function(ko, homeTemplate, service) {
function HomeViewModel(route) {
this.message = ko.observable('Welcome to App!');
}
HomeViewModel.prototype.doSomething = function() {
this.message('You invoked doSomething() on the viewmodel.');
};
return { viewModel: HomeViewModel, template: homeTemplate };
});
I am wondering if there is a better way to do this. For example just being able to use folder name and file name like "services/service"
The paths configuration is your answer (ref). In your configuration do:
require.config({
// ...
paths: {
'services': 'path/to/services/folder'
},
// ...
})
Now you can require the path/to/services/folder/myservice.js module from any other module as:
define(['services/myservice'], function(myservice) {
// ...
});
Related
Is there anyway to set the baseUrl at the path level? I have 1 dependency (my-dependency) in a different folder than the other dependencies. However, when I set the path for that 1 dependency, any dependency that my-dependency has, is relative to the baseUrl of the main app, and not to my-dependency.
I'm looking for something like this maybe:
require.config(
baseUrl: '/js/ad-buys',
paths: {
"my-dependency": {
path: "/js/contacts/my-dependency"
baseUrl: "/js/contacts"
}
}
);
No, that's not possible.
You should not need it anyway. What you describe wanting to do should be achievable by using relative paths for your dependencies. For instance, my-dependency could contain:
define(['./foo'], function (foo) {
});
This would load the module /js/contacts/foo and bind it to the foo parameter of your function . You can also use .. if you need to move up the hierarchy.
I'm trying to create a small EmberJS application, but I'm struggling about how to architecture it correctly. I have a main view called "library" which displays on a sidebar a list of folders. User can click on each folder and display the content at the center (while the sidebar is still active).
I therefore have a library resource, and nested resources to display the folders in this specific context:
this.resource('library', function() {
this.resource('libraryFolders', {path: 'folders'}, function() {
this.resource('libraryFolder', {path: ':folder_id'};
}
};
To be able to access the folders in the parent root, I set up a dependency:
App.LibraryController = Ember.Controller.extend({
needs: ["libraryFolders"],
folders: null,
foldersBinding: "controllers.libraryFolders"
});
App.LibraryRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('controllers.libraryFolders.model', App.Folder.find());
}
});
First question: is this a good way? I feel it a bit strange that a parent controller have a dependency to its children.
Now, another problem arises: what if I want to reuse folders in another context? All the methods I would write in LibraryFoldersController would be specific to this one, not really DRY. What I came up is adding a root "folders" resource, and add the dependency to this one instead:
this.resources('folders');
App.LibraryController = Ember.Controller.extend({
needs: ["Folders"],
folders: null,
foldersBinding: "controllers.folders"
});
App.LibraryRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('controllers.folders.model', App.Folder.find());
}
});
What do you think? Am I doing it wrong?
IMO it looks good so far. You are using the needs API which is the correct (ember) way to setup dependencies between controllers.
Maybe if you find yourself writing repeating code you could consider creating a Mixin for a more general controller an put there your logic, that should be agnostic to the use cases it handles.
For example defined a mixin:
App.ControllerMixin = Ember.Mixin.create({
// "use case" agnostic logic here
});
You mix mixins into classes by passing them as the first arguments to .extend.
App.LibraryController = Ember.ObjectController.extend(App.ControllerMixin, {
// now you can use here the logic defined in your mixin
// and add custom code as you please
});
Another possibility is to write a super class and then extend from it to inherit common logic:
Snippet taken from the docs:
App.Person = Ember.Object.extend({
helloWorld: function() {
alert("Hi, my name is " + this.get('name'));
}
});
var tom = App.Person.create({
name: 'Tom Dale'
});
tom.helloWorld(); // alerts "Hi, my name is Tom Dale".
One thing worth mentioning (though I think it's simply a typo) is: needs: ["Folders"] should be needs: ["folders"],
Hope it helps.
Suppose I have a module that starts like the following:
define(['jquery', 'actions', 'util', 'text!../templates/dialog.html!strip', 'text!../templates/requestRow.html!strip', 'text!../templates/respondForm.html!strip'], function($, actions, util, tDialog, tRequestRow, tRespondForm) {
This module contains most of the code for writing to my client UI. It also loads a couple other modules I've written as well as 3 HTML templates using the text.js plugin. I'm wondering if there's a more concise way of doing this? As the application grows, I may have additional templates to load, or modules and it just seems like my define statement could grow to be a bit ugly. Should I just add my template paths to require.config in my main.js like this:
require.config({
baseUrl: '/webrequests/resources/scripts/',
paths: {
'modernizr': '../js/vendor/modernizr-2.6.2-respond-1.1.0.min',
'bootstrap' : '../js/vendor/bootstrap.min',
'dialog' : 'text!../templates/dialog.html!strip',
'requestRow' : 'test!../templates/requestRow.html!strip',
'respondForm' : 'text!../templates/respondForm.html!strip'
}});
Is there perhaps some way to load all templates within a directory and just have 1 dependency to include in the define statement?
Thanks in advance.
You could make a module for loading in the templates you frequently use. So group the templates to be loaded in one module, that way you can just load this template module instead of the individual templates:
// generalTemplates.js
define([
'text!../templates/dialog.html!strip',
'text!../templates/requestRow.html!strip',
'text!../templates/respondForm.html!strip'
], function (tDialog, tRequestRow, tRespondForm) {
return {
dialog: tDialog,
requestRow: tRequestRow,
respondForm: tRespondForm
};
});
So that in your module, you can simply include the templates like any other module:
define([
'jquery',
'actions',
'util',
'generalTemplates'
], function($, actions, util, templates) {
var tDialog = templates.dialog,
tRequestRow = templates.requestRow,
tRespondForm = templates.respondForm;
/* You can do stuff with the templates here */
});
After another long research, sth comes out :-) It seems the problem is about the function "getObjectByName". It can not work well with requireJS(ADM). Currently, I have to setup a globel var to fix the problem. I am sure there must be have better solution.
Here is my temp soluton:
(1) setup a global var and setup the search model scope to the global ("APP")
var APP = {};
define(['backbone-relational'], function(){
Backbone.Relational.store.addModelScope(APP);
})
(2) export your relation model to the global
APP.YourRelationalModel = YourRelationModel;
It works, not good though... I'm really looking forward to a better answer. Thanks.
//------------
test versions:
1.Backbone-Relational 0.8.5
2.Backbone 1.0.0 and Underscore 1.4.4
3.JQuery 1.8.3
4.RequireJS 2.1.5
Code is very simple: (or see https://github.com/bighammer/test_relational_amd.git)
require.config({
paths : {
js : 'js',
jquery : 'js/jquery-1.8.3',
underscore : 'js/underscore',
backbone : 'js/backbone',
'backbone-relational' : 'js/backbone-relational'
},
shim : {
underscore : {
exports : '_'
},
backbone : {
deps : ['underscore', 'jquery'],
exports : 'Backbone'
},
'backbone-relational' : {
deps: ['backbone']
}
}
});
define(['backbone', 'backbone-relational'], function (Backbone) {
var Child = Backbone.RelationalModel.extend();
var Parent = Backbone.RelationalModel.extend({
relations : [
{
key : 'child',
type : Backbone.HasOne,
relatedModel : 'Child'
}
]
});
var test = new Parent();
});
save above code in main.js and included in index.html as follows:
It doesn't work. There is warning message:
Relation=child: missing model, key or relatedModel (function (){ return parent.apply(this, arguments); }, "child", undefined).
I read the source code of backbone-relational and know there is something wrong with the namespace. Relational-Backbone cannot find the relatedModel defined in "Parent" (i.e. cannot find releatedMode:"Child"). I failed to find the solution to fix this due to my limited knowledge of javascript :-)
Can anyone help me with this?
Before I asked my question, I studied the following solutions:
Backbone.RelationalModel using requireJs
Can't get Backbone-relational to work with AMD (RequireJS)
Loading Backbone.Relational using Use! plugin
None of them worked in this case.
You don't have to reference relatedModel by string, you can reference it directly, so instead of relatedModel: 'Child', just use: relatedModel: Child.
And since you are using requireJS, you can reference model from other file easily.
define(['backbone', 'models/child', 'backbone-relational'], function (Backbone, Child) {
var Parent = Backbone.RelationalModel.extend({
relations : [{
key : 'child',
type : Backbone.HasOne,
relatedModel : Child
}]
});
var test = new Parent();
});
The above solution didn't apply to me. I am gradually moving code out of Rails Asset Pipeline (not RequireJS/AMD/CommonJS/anything) into Webpack, starting with dependencies. When I moved requiring backbone-relational into Webpack bundle preparation by my models and relation definitions were still in Rails Asset Pipeline, I started getting a lot of unexplained Relation=child: missing model, key or relatedModel (function (){ return parent.apply(this, arguments); }, "child", undefined).
In my case, the solution ended up being quite simple, despite taking a long time to discover on my part:
// In a Webpack module, later included into Rails Asset Pipeline
// temporarily to facilitate migration
require('expose?Backbone!backbone') // Exposing just for migration
require('backbone-relational')
Backbone.Relational.store.addModelScope(window)
backbone-relational by default uses its global scope to resolve string-based relatedModels but since it was required without a real global scope, the solution is simply to pass that in using addModelScope so it can search that scope for the specified models.
I'm trying to define a global object that i can reference across all of my modules. however, in the modules, i am unable to reference my path, and it's saying that "g" does not exist.
In main1.js, i have this:
requirejs.config({
paths: {
Underscore: 'lib/underscore/1.3.3/underscore.min',
Backbone: 'lib/backbone/0.9.2/backbone.min',
Globals: 'lib/backbone/ globalVars'
}
});
require([ 'views/pages', 'views/filters'], function(allPages, filters) {
filters.render();
allPages.render();
});
inside globalVars.js, i have this:
(function() {
var Globals = {
isDemo: false
}
console.log('in globalvars') // this shows in my console
}).call(this);
and finally, inside of view/pages.js, i have this:
define([
'Globals',
'Underscore',
'Backbone'
], function(g, _, Backbone){
console.log(g.isDemo) //<-- returns "TypeError: g is undefined"
If i use a define inside my main1.js like this:
define( 'Globals', function() {
return {
isDemo: true
}
})
it works just fine. I haven't had much luck with trying to figure out why this is not working. I'd like to be able to just include a path to the globalVars rather than boilerplate pasting a define block in each and every module that needs it, since changing isDemo to false would require updating many other module pages (main2.js, main3.js, etc) as well. thanks!
Well, to start with, your globalVars.js is not in the module pattern, so requirejs doesn't know what you're trying to register as the module. If you change that file to use the pattern, like the define you added to main1.js, you should be all set. Is there a reason you aren't defining it as a module?