Nested Resources in ember-cli, messy app structure - javascript

As a newbie to both Ember.js and ember-cli, I'm having trouble making sense of what seems necessary to make my app work.
The logical hierarchy of my app is something like this:
Projects
|___Project
|___Details
|___Team Members
|___Budget
|___Planned
|___Actual
And currently, this is my router.js:
this.resource('projects');
this.resource('project', { path: 'projects/:project_id' }, function() {
this.route('details');
this.route('team');
this.route('milestones');
this.resource('budget', function(){
this.route('project-budget', { path: 'project'});
this.route('resource-budget', {path: 'team'});
});
});
What I'm having trouble with is where to put my files. Up until the point of the two nested routes under Budget, my folder structure looked like my hierarchy, but since a Resource resets the namespace, now to make it work I have to pull my Budget template, route, and controller back out to the top level (with Projects stuff), which just seems messy and like it will cause headaches when trying to maintain this thing later.
Am I doing it wrong?

Router definition can be a little tricky in Ember. Your resource/route definition in router.js should reflect your page structure. So for example, if your 'team' template should be nested inside your 'project' template, then 'team' should be nested inside of 'project' in router.js:
Router.map(function() {
this.resource('project', function() {
this.route('team');
});
});
If you use this.route() in router.js, then your folder structure should mimic the structure in router.js. Using the example above, because we're using this.route() to define 'team', your folder structure would be like this:
app/routes/project.js
app/routes/project/team.js
app/templates/project.hbs
app/templates/project/team.hbs
If, however, you choose to use use this.resource() in router.js, then you're telling Ember that you're going to reset your folder structure. So if you changed router.js to this:
Router.map(function() {
this.resource('project', function() {
this.resource('team');
});
});
...then your folder structure would be like this:
app/routes/project.js
app/routes/team.js
app/templates/project.hbs
app/templates/team.hbs
Going back to your specific question, if you feel that resetting your folder structure is messy, then you can use this.route() everywhere and forego this.resource(), because nestable this.route() landed in Ember 1.7: http://emberjs.com/blog/2014/08/23/ember-1-7-0-released.html

Related

How do I register a Vue component?

I have the following files. All I want to do is to be able to create different components that are injected. How do I achieve this using require.js? Here are my files:
main.js
define(function(require) {
'use strict';
var Vue = require('vue');
var myTemplate = require('text!myTemplate.html');
return new Vue({
template: myTemplate,
});
});
myTemplate.html
<div>
<my-first-component></my-first-component>
</div>
MyFirstComponent.vue
<template>
<div>This is my component!</div>
</template>
<script>
export default {}
</script>
I'm going to assume you're using webpack as explained in the Vue.js docs, or else your .vue file is useless. If you're not, go check how to set up a webpack Vue app first, it's what lets you use .vue files.
import Menubar from '../components/menubar/main.vue';
Vue.component('menubar', Menubar);
That's how you add e.g. a menubar component to the global scope. If you want to add the component to just a small part of your app, here's another way of doing it (this is taken from inside another component, but can be used in exactly the same manner on your primary Vue object):
import Sidebar from '../../components/sidebar/main.vue';
export default {
props: [""],
components: {
'sidebar': Sidebar
},
...
You can load components without webpack, but I don't recommend it, if you're gonna keep using Vue (which I strongly suggest you do) it's worth it to look into using webpack.
Update
Once again, really, really, really consider using webpack instead if you're gonna be continuing with Vue.js, the setup may be slightly more annoying but the end result and development process is waaaay better.
Anyway, here's how you'd create a component without webpack, note that without webpack you can't use .vue files since the .vue format is part of their webpack plugin. If you don't like the below solution you can also use e.g. ajax requests to load .vue files, I believe there is a project somewhere out there that does this but I can't find it right now, but the end result is better with webpack than with ajax anyway so I'd still recommend going with that method.
var mytemplate = `<div>
<h1>This is my template</h1>
</div>`
Vue.component('mycomp1', {
template: mytemplate
});
Vue.component('mycomp2', {
template: `
<div>
Hello, {{ name }}!
</div>
`,
props: ['name'],
});
As you can see, this method is A LOT more cumbersome. If you want to go with this method I'd recommend splitting all components into their own script files and loading all those components separately prior to running your actual app.
Note that `Text` is a multi line string in javascript, it makes it a little easier to write your template.
And as I said, there is some project out there for loading .vue files using ajax, but I can't for the life of me find it right now.

How to share objects/methods between controllers without circular references?

Pretty straightforward question. Currently, what I do when I need to access objects' methods throughout most of the application, I do this in app.js
Ext.define('Utils', {
statics: {
myMethod: function() {
return 'myResult';
}
}
});
This works, but when I build the application, I get a warning about a circular reference (app.js of course needs all the other controller classes, but then said classes refer back to app.js).
I thought of using a package including a .js file that has all the objects/methods, but sometimes, within these methods I'll need access to the Ext namespace so that won't work.
Is there any better way to do this ?
Thanks!
You should not define the class Utils inside app.js. Each Ext.define statement should be in it's own file. Also the classname should be prefixed with your app name.
Ext.define('MyApp.Utils', {
statics: {
myMethod: function() {
return 'myResult';
}
}
});
should therefore be found in the file app/Utils.js. When compiling your sources into a compiled app.js, Sencha Cmd will take care of the proper ordering in the final file. The requires and uses directives give you enough flexibility to define any dependences between your classes.
Read all the docs about MVC to get a clear understanding.

How to create two separate pages in ember

I am trying to integrate ember into my grails app. I've got one page working in Ember but am unsure of how to have two different pages.
I have a page called color.gsp the server does nothing but just redirects to this page so the method is just def color() {}
In this page I have several templates one of which is Application template. I have a App.js which handles everything on this page and everything is working fine on this page.
Question
Now I want to have another page called shade.gsp where also the server should not do anything by redirect so again the method will simply be def shade() {}.
The problem is, how would App.js know whether to update application template in shade.gsp or color.gsp.
I understand this might not be the ideal way to do things in ember. but since I'm integrating ember rather than complete overwrite, i need this option to work. Is there a way I can have separate JS files for color and shade?
I think that changing your js structure, to reflect your dependencies can solve this problem.
// App.js
App.Router.map(function() {
this.route('color');
this.route('shade');
});
// Color.js
// here all color resources
App.ColorRoute = Ember.Route.extend({
// your implementation
});
// Shade.js
// here all shade resources
App.ShadeRoute = Ember.Route.extend({
// your implementation
});
In your ApplicationResources.groovy
modules = {
application {
dependsOn 'jquery', 'handlebars', 'ember'
resource url:'js/App.js'
}
shade {
dependsOn 'application'
resource url: 'js/Shade.js'
}
color {
dependsOn 'application'
resource url: 'js/Color.js'
}
}
In shade.gsp
<r:require modules="shade"/>
In color.gsp
<r:require modules="color"/>

Jasmine not finding Backbone.js Models

I've just started using Jasmine with maven. I have Jasmine working, but for some reason it cannot find my Backbone models. I have the JavaScript src directory pointing to the folder containing my Backbone.js models. In my JavaScript test directory I have a simple test as such:
describe('ToDo Model',function()
{
it('Test',function() {
var todo = new ToDo();
});
});
But I keep getting ToDo is not defined. Do I have to write my tests inside of the my backbone model files or anything? Thanks.
ToDo has to be in the global namespace as well. Try typing this in your Chrome/Firefox console:
window.ToDo
If it returns undefined, then that's the problem!
It's usually a good practice to define a global namespace for your app, for example:
window.Application = {
Models: {},
Views: {},
Collections: {}
}
// etc.
Then, I like to define models like this:
(function (Models) {
Models.ToDo = Backbone.Models.extend({
// etc...
});
})(Application.Models);
The namespacing here isn't necessary, but seeing Models right at the top of the file is a nice visual cue, I think.

Where do I put the code to bootstrap a collection into backbone.js?

I am new to javascript and I saw another post with a similar question but I'm not sure how to actually inject models into a backbone.js that lives in a separate file.
In my index file I have the following which is starting the app:
$(function () {
var app = new App();
Backbone.history.start();
});
Inside my application.js file I have the router which needs to have customers:
window.App = Backbone.Router.extend({
routes: {
"": "home"
},
home: function () {
console.log("route::home");
console.log(this.customers);
}
});
How can I actually get this.customers to be injected into the application? Where does this code live?
I wrote an article that outlines how code like what you've shown here is potentially an anti-pattern, and illustrates a simple way of getting the data bootstrapped. Though your direct question is not the purpose of this article, I think the contents of this article should lead you in a direction that does solve the problem your running in to.
http://lostechies.com/derickbailey/2011/08/30/dont-limit-your-backbone-apps-to-backbone-constructs/

Categories