When building a relatively large application, how should I define my router? More specifically, if using requirejs I have the following code:
main.js
define('application',['routes/app_router'], function(router){
return Ember.Appcliation.create(
LOG_TRANSITIONS:true,
...
});
requirejs('application',function(application){
var App = window.App = application;
...
}
and in the routes/ I have app_router.js
define('app_router',['ember'],function(){
...
});
So should I pass an app to my app_router to set the App.Router.map... method or should I return a Ember.Router.map(...)? If the first variant is chosen then for sure, the dependencies change.
In other words, should I create an "empty" Ember.Application and pass it to the router so it can define the App.Route.map(... method, since it has reference to this, like this.route\this.resource..., or should I invoke Ember.Router.create() then invoke the map function on it, then return this from the module and set it to App.Router = router.
So should I pass an app to my app_router to set the App.Router.map... method or should I return a Ember.Router.map(...)? If the first variant is chosen then for sure, the dependencies change.
I'd go with the 2nd variant.
In other words, should I create an "empty" Ember.Application and pass it to the router so it can define the App.Route.map(... method, since it has reference to this, like this.route\this.resource..., or should I invoke Ember.Router.create() then invoke the map function on it, then return this from the module and set it to App.Router = router.
Neither. You should let ember create the router itself. All your code should be doing is calling App.Router's map fx. I'm no require.js expert, but something like this should work:
//Define a fx that specifies your applications routes
define('routes',['ember'], function(){
return function() {
this.route("about");
}
});
// Pass that custom routes fx to App.Router.map before routing begins
define('application',['routes'], function(routes){
return Ember.Application.create({
LOG_TRANSITIONS: true,
ready: function() {
this.Router.map(routes);
}
});
Here's a jsfiddle showing the basic concept, without require.js of course.
Related
In my Ember app I'm using ember-inject-script which I installed:
npm install --save-dev ember-inject-script
The controller.js file for my page looks like this:
import Ember from 'ember';
import injectScript from 'ember-inject-script';
export default Ember.Controller.extend({
init: function() {
this._super();
var url = "https://meet.jit.si/external_api.js";
injectScript(url);
var domain = "meet.jit.si";
var room = "JitsiMeetAPIExample";
var width = 700;
var height = 700;
var htmlElement = document.querySelector('#meet');
var api = new JitsiMeetExternalAPI(domain, room, width, height,
htmlElement);
}
});
The Template is this:
<h2>Jitsi Meet</h2>
<div id="meet"></div>
{{outlet}}
Yet I get a console error:
Error while processing route: projects.index JitsiMeetExternalAPI is not defined ReferenceError: JitsiMeetExternalAPI is not defined
injectScript in asynchronous so you can't use JitsiMeetExternalAPI very next statement. You need to use then.
Another issue is, you are accessing the DOM element in controller init method, which will not be available. generally controller is not DOM aware. for this I will encourage you to write Component and use didInsertElement hook
One more alternative approach to load js at the required time, is in routes beforeModel hook, you can just use Ember.$.getJSON(url).
beforeModel(){
return Ember.$.getJSON(url);
}
Im building an Ember app "ember-cli": "2.4.3", sitting on Laravel/Lumen and cant seem to get the wires hooked up correctly. Im trying to also an API server JSON-API compliant, so I have access to alter the syntax if thats a problem.
If I remove the export default DS.JSONAPISERIALIZER, I get ember.debug.js:32116 TypeError: typeClass.eachTransformedAttribute is not a function
With it, I typically get Assertion Failed: You tried to load all records but your adapter does not implement findAll
If I call getJSON(...) from within the route, instead to calling the store for the data, it works perfectly, and displays to the view as expected.
I have tried other adapters but I think that being JSON-API compliant I need to use the JSONAPIADAPTER. Any help would be awesome.
application.js
import DS from "ember-data";
export default DS.JSONAPIAdapter.extend({
namespace: 'v1',
host: 'http://edu-api.app:8000',
});
export default DS.JSONAPISerializer.extend({
//in preparation of underscores in returned data
// keyForAttribute: function(attr) {
// return Ember.String.underscore(attr);
// },
// keyForRelationship: function(attr) {
// return Ember.String.underscore(attr);
// }
});
skill.js
import DS from 'ember-data';
var App = window.App = Ember.Application.extend();
var attr = DS.attr;
App.Skill = DS.Model.extend({
name: attr("string"),
desc: attr("string")
});
index.js
export default Ember.Route.extend({
model() {
//return this.store.findAll('skill'); //<- Assertion Failed: You tried to load all records but your adapter does not implement `findAll`
this.get('store').findAll('skill'); //<- Assertion Failed: You tried to load all records but your adapter does not implement `findAll`
//return Ember.$.getJSON('http://edu-api.app:8000/v1/skills'); //<- works, and properly displays data to view
}
});
I think you primary have problems understanding ember-cli.
First you don't put your adapter and serializer in the same file. Maybe use the generators to get a default file like ember generate serializer application.
Your application serializer goes to app/serializers/application.js, your adapter to app/adapters/application.js.
Next this line looks really really wrong:
var App = window.App = Ember.Application.extend();
This creates a new app, but you should do this only once in your app/app.js. Next you use a global export, what you should never do in an ember-cli app.
To specify your model you need to locate your file under models/skill.js. There you don't attach your new Model to a global exported App like App.Skill = DS.Model.extend({, but you export it as default export like export default DS.Model.extend({.
Your index.js looks right if its located under routes/.
I strongly recommend you to read more about the ember resolver, and the ember dependency injection framework which do all this magic for you. Also use the generators to get your files, it can help you to place your files right.
I'm starting a marionette app and I try to structure it. So now I have:
define(["marionette", "handlebars", "routes"], function(Marionette, Handlebars, Route){
var App = new Marionette.Application();
...
App.addRegions({
header: "#header_region",
...
});
App.addInitializer(function(options){
...
new Route();
Backbone.history.start();
});
return App;
});
and my routes looks like:
define(["marionette", "app", "header/view"], function(Marionette, App, headerView){
var Route = Backbone.Marionette.AppRouter.extend({
routes : {
'' : 'home'
},
home: function(){
var header_view = new headerView();
App.header.show(header_view);
...
}
});
return Route;
});
Obviously I have a loop in dependencies here with App.header.show(header_view). What is the common way to solve it? How do you structure your Marionette app?
This was a great example that helped to get me going when building my first Marionette App: https://github.com/BoilerplateMVC/Marionette-Require-Boilerplate/tree/master/public/js/app
The way you currently have your route file set up is the backbone way of doing it. You should create a Marionette Controller that will respond to the App routes.
Also, you'll see that this person creates init files to specify all of the start up logic (specifying global static variables and instantiating the controller and router to be used).
Hope this helps!
In a new ember App you write first:
var App = Ember.Application.create({
test: 'foo',
...
});
In a new ember-cli App you write first:
var App = Ember.Application.extend({
test: 'foo',
...
});
Why?
( In the second case, I can't read a global property (App.test) from a controller. !? )
This question actually has a lot to do with Ember.Object.
.extend() creates a new class that extends the old one, with class-level properties defined in the hash that is passed in.
.create() create a new instance of the class, with object-level properties defined in the hash that is passed in.
This is why you cannot read the property in the second case. If you want to do that, you will need to do:
var App = Ember.Application.extend({});
App.test = 'foo';
In a plain Ember app, you can create an instance of the App object, because you are going to use it directly.
In an ember-cli generated Ember app, you do not create an instance of the App object, you merely define its class (using .extend()). This is because you do not use it directly, as ember-cli wants the class, so that it may do its own things to it, before it internally instantiates it.
I have a module like the following defined in one file
define(['mod1', 'mod2'], function (mod1, mod2) {
var IndexView = Backbone.View.extend({
...
});
return new IndexView;
});
And this is required from within another file (my Backbone router file) with the following
require(['src/views/index']);
Can I make the returned IndexView object accessible from within the router's scope without resorting to storing a reference in my app's namespace?
Passing around instances of Backbone views/models with require.js will quickly make your life very unhappy. It would be much easier to make your modules only return the definitions of the views/models, that way can instantiate them all inside the same scope.
So if you make your view module return just the definition:
// IndexView module
define(['dep1', 'dep2'], function (dep1, dep2) {
var IndexView = Backbone.View.extend({
...
});
return IndexView;
});
You can then instantiate it inside your router:
// our main requirejs function
requirejs(['path/to/indexview'], function (IndexView) {
var AppRouter = Backbone.Router.extend({
initialize: function () {
// bind our IndexView to the router
this.IndexView = new IndexView();
}
});
// start the app
var app = new AppRouter();
});
That way your code is still modular with Require.js, but you can pass around the router's scope using this.