Ember - linking to JSON file - javascript

I'm working through a tutorial/example from codeschool. It's all working nicely but the example is using
App.ApplicationAdapter = DS.FixtureAdapter.extend();
and I would like to now keep everything exactly as it is, but move the product data to an external JSON file.
Here is my app.js file:
var App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Router.map(function(){
this.route('about', {path:'/aboutus'});
this.resource('products', function() {
this.resource('product', { path: '/:product_id' });
});
});
App.ApplicationAdapter = DS.FixtureAdapter.extend();
App.IndexController = Ember.Controller.extend ({
productsCount: 6,
logo: 'images/logo.png',
time: function() {
return (new Date()).toDateString()
}.property()
});
App.Product = DS.Model.extend({
title: DS.attr('string'),
price: DS.attr('number'),
description: DS.attr('string'),
isOnSale: DS.attr('boolean'),
image: DS.attr('string'),
reviews: DS.hasMany('review', {async:true})
});
App.Review = DS.Model.extend ({
text: DS.attr('string'),
reviewedAt: DS.attr('date'),
product: DS.belongsTo('product')
});
App.ProductsRoute = Ember.Route.extend({
model: function() {
return this.store.findAll('product');
}
});
App.Product.FIXTURES = [
{
id: 1,
title: 'Flint',
price: 99,
description: 'Flint is a hard, sedimentary cryptocrystalline form of the mineral quartz, categorized as a variety of chert.',
image: 'images/products/flint.png',
reviews: [100,101]
},
{
id: 2,
title: 'Kindling',
price: 249,
description: 'Easily combustible small sticks or twigs used for starting a fire.',
image: 'images/products/kindling.png',
reviews: [100,101]
}
];
App.Review.FIXTURES = [
{
id: 100,
product: 1,
text: "Sarted a fire in no time"
},
{
id: 101,
product: 1,
text: "Not the brightest flame of the flame"
}
];
Here is my HTML (index.html) file:
<!DOCTYPE html>
<html>
<head>
<script src="jquery-1.10.2.js"></script>
<script src="handlebars-v2.0.0.js"></script>
<script src="ember-1.9.1.js"></script>
<script src="ember-data.js"></script>
<script src="app.js"></script>
<script src="products.json"></script>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body>
<script type='text/x-handlebars' data-template-name='application'>
{{#link-to 'index'}}Homepage{{/link-to}}
{{#link-to 'about'}}About{{/link-to}}
{{#link-to 'products'}}Products{{/link-to}}
<div class='navbar'>..</div>
<div class='container'>{{outlet}}</div>
<footer class='container'>..</div>
</script>
<script type='text/x-handlebars' data-template-name='index'>
<h1>Welcome to the Flint & Flame!</h1>
<p>There are {{productsCount}} products</p>
<img {{bind-attr src='logo'}} alt='logo' />
<p>Rendered on {{time}}</p>
</script>
<script type='text/x-handlebars' data-template-name='about'>
<h1>About the Fire Spirits</h1>
</script>
<script type='text/x-handlebars' data-template-name='products'>
<div class='row'>
<div class='col-md-3'>
<div class='list-group'>
{{#each}}
{{#link-to 'product' this classNames='list-group-item'}}
{{title}}
{{/link-to}}
{{/each}}
</div>
</div>
<div class='col-sm-9'>
{{outlet}}
</div>
</div>
</script>
<script type='text/x-handlebars' data-template-name='product'>
<div class ='row'>
<div class ='col-md-7'>
<h1>{{title}}</h1>
<p>{{description}}</p>
<p>Buy for $ {{price}}</p>
</div>
<div class='col-md-5'>
<img {{bind-attr src='image'}} class ='img-thumbnail' 'img-rounded' />
</div>
<h3>Reviews</h3>
<ul>
{{#each reviews}}
<li>{{text}}</li>
{{else}}
<li><p class='text-muted'>
<em>No reviews yet</em>
</p><li>
{{/each}}
</ul>
</div>
</script>
<script type='text/x-handlebars' data-template-name='products/index'>
<p class='text-muted'>Choose a product</p>
</script>
</body>
</html>
The tutorial says to create a json file with the following in it:
{"products": [
{
"id": 1,
"title": "Flint",
"price": 99,
"description": "Flint is a hard, sedimentary cryptocrystalline form of the mineral quartz, categorized as a variety of chert.",
"isOnSale": true,
"image": "images/products/flint.png",
"reviews": [100,101]
},
{
"id": 2,
"title": "rfgergerg",
"price": 34,
"description": "sdfdfsdfsdfsdf, categorized as a variety of chert.",
"isOnSale": false,
"image": "images/products/flint.png",
"reviews": [100,101]
}
],
"reviews": [
{"id": 100, "product":1, "text": "efefefefefe"}
]
}
and then to change
App.ApplicationAdapter = DS.FixtureAdapter.extend();
to:
App.ApplicationAdapter = DS.RESTAdapter.extend();
etc.
I can't seem to link to this JSON file. I just wanted to know, should I add anything else to the above ApplicationAdapter? Am I right to include the JSON file in the head of my HTML file?
Basically just need some assistance in making the above example, which works fine, use an external JSON file instead.
Thanks!
UPDATE
I suppose to make this questions a bit simpler:
I have an index.html file, an app.js file, and a products.json file , all in the same directory
I want to use this in my app.js file:
App.ApplicationAdapter = DS.RESTAdapter.extend({
xxxxxxxxx
});
What do I put in 'xxxxxx' to load my json file?
Thanks!
UPDATE
Ok, I have figured this out duh!
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: '/name of directory'
});
In my case my project is at localhost/ember
and the following works:
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: '/ember'
});

I had the same problem.
Instead of linking to the JSON file from the HTML you must extend the DS.RESTAdapter with a request to your file, like this:
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: '/products.json?jsonp=?'
});
This should work.
Let me know!

App.ApplicationAdapter = DS.RESTAdapter.extend({
host: '/name of directory'
});
Also note that I had to remove the .json extension from my file. Now it's just call products (a text file). When I add the .json extension it can't find the file.

Related

Meteor dynamic category list

I would like to do the following. I would like to create a categories page that loads each category onto a picture. Then when a user clicks a category the parameter would show up on the url and it will search the database for photos based on that category. I will now demonstrate the code that I have.
Categories HTML File:
<template name="categories">
<div class="text-center light-container" id="categories-section">
<h1>Categories</h1>
<hr/>
{{#each categories}}
<div class="image-container">
<a href="{{pathFor route='categoryPage'}}">
<img class="freezeframe pics" src="images/app/sphere.jpg"/>
</a>
<h2><span>{{categories}}</span></h2>
</div>
{{/each}}
</div>
</template>
Categories JS File:
var categoryList = ['actions', 'animals', 'anime', 'art/design', 'cartoons/comics', 'celebrities',
'Emotions', 'Food/Drink', 'Games', 'History', 'Holidays', 'Memes', 'Movies', 'Music', 'Nature', 'News/Politics',
'Science', 'Sports', 'Technology', 'TV'];
Template.categories.helpers({
'categories':function(){
for(var i = 0; i < categoryList.length; i++){
console.log(categoryList[i]);
return categoryList[i];
}
}
});
Router JS File:
Router.route('/categories', {
name: 'categories',
template: 'categories',
fastRender: true
});
Router.route('/categories/:category', {
name: 'categoryPage',
template: 'categoryPage',
data: function(){
var category = this.params.category;
return GifsCollection.find({category: category});
},
fastRender: true
});
CategoryPage JS:
Template.categoryPage.helpers({
// Load 16 most recent ones
// When down arrow is click load another 16 more gifs
gifs: function() {
var category = this.params.category;
return GifsCollection.find({category: category}, {fields: {_id: 1, image: 1} });
}
});
Running the following code doesn't get me anywhere. I'm not sure which path to take. I can create a 'category' collection and load the helpers onto there or I can use sessions? but I'm leaning onto creating category collection however I'm pretty sure there is a much more efficient way.
Any feedback and code help would be greatly appreciated!!!
You have two small errors. One we already discussed in comments, regarding the helper. The other is in how you use the #each loop: inside of it you can just refer to this to get the string of your category.
Categories HTML File:
<template name="categories">
<div class="text-center light-container" id="categories-section">
<h1>Categories</h1>
<hr/>
{{#each categories}}
<div class="image-container">
<a href="/categories/{{this}}">
<img class="freezeframe pics" src="images/app/sphere.jpg"/>
</a>
<h2><span>{{this}}</span></h2>
</div>
{{/each}}
</div>
</template>
Categories JS File:
var categoryList = ['actions', 'animals', 'anime', 'art/design', 'cartoons/comics', 'celebrities',
'Emotions', 'Food/Drink', 'Games', 'History', 'Holidays', 'Memes', 'Movies', 'Music', 'Nature', 'News/Politics',
'Science', 'Sports', 'Technology', 'TV'];
Template.categories.helpers({
'categories':function(){
return categoryList;
}
});

EmberJS - object proxying is deprecated - accessing property of a controller in template

I'm trying to understand certain peculiarity.
Setting xxx property and iterating #each in one controller works, while seemingly same operation with yyy #each doesn't...
I'm including highlights of the code and the runnable code snippet:
App.IndexController = Ember.Controller.extend({
xxx : [{name:"a"}, {name:"b"}], // this works just fine
});
{{#each item in xxx}}
<li>{{item.name}}</li>
{{/each}}
App.ColorController = Ember.Controller.extend({
yyy : [{name:"c"}, {name:"d"}], // this triggers deprecation
// You attempted to access `yyy` from ...
// But object proxying is deprecated. Please use `model.yyy` instead
});
{{#each item in yyy}}
<li>{{item.name}}</li>
{{/each}}
App = Ember.Application.create();
App.Color = DS.Model.extend({
name: DS.attr('string')
});
App.Router.map(function() {
this.resource('color', function(){
this.route('show', { path: ':color_id' });
});
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return [
{ id: 1, name: "Red" },
{ id: 2, name: "Blue" },
];
}
});
App.IndexController = Ember.Controller.extend({
xxx : [{name:"a"}, {name:"b"}], // this works just fine
});
App.ColorController = Ember.Controller.extend({
init : function() {
this._super();
console.info("Just to double check, this controller gets initialised");
},
yyy : [{name:"c"}, {name:"d"}], // this triggers deprecation
// You attempted to access `yyy` from ...
// But object proxying is deprecated. Please use `model.yyy` instead
});
<script type="text/x-handlebars">
<h2>Ember Starter Kit</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" id="index">
<h3>Index</h3>
<ul>
{{#each color in model}}
<li>{{#link-to "color.show" color}} {{color.name}} {{/link-to}}</li>
{{/each}}
</ul>
<ul>
{{#each item in xxx}}
<li>{{item.name}}</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" id="color/show">
<h3>color/show</h3>
<h4>{{ model.name }}</h4>
<ul>
{{#each item in yyy}}
<li>{{item.name}}</li>
{{/each}}
</ul>
{{#link-to "application"}}Go back to the list{{/link-to}}
</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="http://builds.emberjs.com/tags/v1.13.2/ember.debug.js"></script>
<script src="http://builds.emberjs.com/tags/v1.13.2/ember-template-compiler.js"></script>
<script src="http://builds.emberjs.com/tags/v1.13.2/ember-data.js"></script>
I'd like to learn more:
why it works in one case and doesn't work in another?
what is the Ember way of fixing it?
EDIT: Updated code snippet include Color model. To trigger deprecation warning click on one of the colours (Red, Blue)... This is what happens when I run the snippet:
Okay, as I expected - problem lies in naming conventions and relics of the past(ObjectController). Declaring ColorController creates controller for model, not a route. You need here controller for route, so changing ColorController to ColorShowController solves problem and values render. Deprecation's gone.
App = Ember.Application.create();
App.Color = DS.Model.extend({
name: DS.attr('string')
});
App.Router.map(function() {
this.resource('color', function(){
this.route('show', { path: ':color_id' });
});
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return [
{ id: 1, name: "Red" },
{ id: 2, name: "Blue" },
];
}
});
App.IndexController = Ember.Controller.extend({
xxx : [{name:"a"}, {name:"b"}], // this works just fine
});
App.ColorShowController = Ember.Controller.extend({
init : function() {
this._super();
console.info("Just to double check, this controller gets initialised");
},
yyy : [{name:"c"}, {name:"d"}], // this triggers deprecation
// You attempted to access `yyy` from ...
// But object proxying is deprecated. Please use `model.yyy` instead
});
<script type="text/x-handlebars">
<h2>Ember Starter Kit</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" id="index">
<h3>Index</h3>
<ul>
{{#each color in model}}
<li>{{#link-to "color.show" color}} {{color.name}} {{/link-to}}</li>
{{/each}}
</ul>
<ul>
{{#each item in xxx}}
<li>{{item.name}}</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" id="color/show">
<h3>color/show</h3>
<h4>{{ model.name }}</h4>
<ul>
{{#each item in yyy}}
<li>{{item.name}}</li>
{{/each}}
</ul>
{{#link-to "application"}}Go back to the list{{/link-to}}
</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="http://builds.emberjs.com/tags/v1.13.2/ember.debug.js"></script>
<script src="http://builds.emberjs.com/tags/v1.13.2/ember-template-compiler.js"></script>
<script src="http://builds.emberjs.com/tags/v1.13.2/ember-data.js"></script>

Ember.js - Hiding parent views in nested resources

I'm building a web video app that functions in a similar way to YouTube. My desired URL path is appname.com/video-title/video-id. I've represented it in this way:
App.Router.map(function() {
this.resource('videos', { path: '/:video_title' }, function(){
this.resource('video', { path: '/:video_id' });
});
});
The problem that I'm having is that the video-id url is also displaying the video-title template.
The video-title url should display search results of that video name and the video-id url should display the specific video and play it in a video player.
HTML:
<script type="text/x-handlebars" data-template-name="videos">
<ul>
{{#each video in model}}
<li>{{video.title}} by {{video.author}}</li>
{{/each}}
</ul>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="videos">
<p>{{title}}</p>
</script>
Model:
var videos = [{
id: '1',
title: 'Skiing in Tahoe',
author: 'daniel'
},{
id: '2',
title: 'Exploring San Francisco',
author: 'nickmillerza'
}];
I'm new to Ember - perhaps I shouldn't use it for an app like this?
You can totally do this
App.VideoRoute = Ember.Route.extend({
model: function(params){
// return model
},
renderTemplate: function(controller) {
// render it into the videos outlet
this.render('videos', {controller: controller});
}
});

Emberjs not working when using url directly

I'm new to EmberJs and was following this post from Adam Hawkins. When I tried to run this in a browser it seems to work but not as expected. when I click a dj in the navigation bar (data-template-name="djs") the browser navigates to the detail of the choosen dj and shows me all his albums. e.g. embertest/index.html#/djs/djs/armin-van-buuren
But if I paste the url (embertest/index.html#/djs/djs/armin-van-buuren) directly in the browser without clicking a dj first in the navigation list I get the message "No Albums" from the handlebars template "djs/dj"
I would expect the same behavior in both scenario's. What am I missing here?
For completeness you can find my ember application and handlebar templates below.
app.js
var App = Ember.Application.create(
{ LOG_TRANSITIONS: true,
LOG_BINDINGS: true,
LOG_VIEW_LOOKUPS: true,
LOG_STACKTRACE_ON_DEPRECATION: true,
LOG_VERSION: true,
debugMode: true
});
window.App = App;
App.DJS = [
{
name: 'Armin van Buuren',
albums: [
{
name: 'A State of Trance 2006',
cover: 'http://upload.wikimedia.org/wikipedia/en/thumb/8/87/ASOT_2006_cover.jpg/220px-ASOT_2006_cover.jpg'
},
{
name: '76',
cover: 'http://upload.wikimedia.org/wikipedia/en/thumb/8/8a/Armin_van_Buuren-76.jpg/220px-Armin_van_Buuren-76.jpg'
},
{
name: 'Shivers',
cover: 'http://upload.wikimedia.org/wikipedia/en/thumb/a/a1/ArminvanBuuren_Shivers.png/220px-ArminvanBuuren_Shivers.png'
}
]
},
{
name: 'Markus Schulz',
albums: [
{
name: 'Without You Near',
cover: 'http://upload.wikimedia.org/wikipedia/en/9/92/Markus_Schulz_Without_You_Near_album_cover.jpg'
},
{
name: 'Progression',
cover: 'http://upload.wikimedia.org/wikipedia/en/thumb/8/81/Markus-schulz-progression_cover.jpg/220px-Markus-schulz-progression_cover.jpg',
},
{
name: 'Do You Dream?',
cover: 'http://upload.wikimedia.org/wikipedia/en/thumb/9/92/Doyoudream.jpg/220px-Doyoudream.jpg',
}
]
},
{
name: 'Christopher Lawrence',
albums: [
{
name: 'All or Nothing',
cover: 'http://s.discogss.com/image/R-308090-1284903399.jpeg',
},
{
name: 'Un-Hooked: The Hook Sessions',
cover: 'http://s.discogss.com/image/R-361463-1108759542.jpg'
}
]
},
{
name: 'Above & Beyond',
albums: [
{
name: 'Group Therapy',
cover: 'http://s.discogss.com/image/R-2920505-1345851845-3738.jpeg'
},
{
name: 'Tri-State',
cover: 'http://s.discogss.com/image/R-634211-1141297400.jpeg',
},
{
name: 'Tri-State Remixed',
cover: 'http://s.discogss.com/image/R-1206917-1200735829.jpeg'
}
]
}
];
App.Router.map(function() {
this.resource('djs', function() {
this.route('dj', { path: '/djs/:name' });
});
});
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('djs');
}
});
App.DjsRoute = Ember.Route.extend({
model: function() {
return App.DJS;
}
});
App.DjsDjRoute = Ember.Route.extend({
serialize: function(dj) {
return {
name: dj.name.dasherize()
}
}
});
Index.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<!-- application template -->
<script type="text/x-handlebars">
<div class="navbar navbar-static-top">
<div class="navbar-inner">
{{#linkTo 'djs' class="brand"}}On The Decks{{/linkTo}}
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
{{outlet}}
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="djs">
<div class="span2">
<ul class="nav nav-list">
{{#each controller}}
<li>{{#linkTo 'djs.dj' this}}{{name}}{{/linkTo}}
{{/each}}
</ul>
</div>
<div class="span8">
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="djs/dj">
<h2>{{name}}</h2>
<h3>Albums</h3>
{{#if albums}}
<ul class="thumbnails">
{{#each albums}}
<li>
<div class="thumbnail">
<img {{bindAttr src="cover" alt="name"}} />
</div>
</li>
{{/each}}
{{else}}
<p>No Albums</p>
{{/if}}
</script>
<script type="text/x-handlebars" data-template-name="djs/index">
<p class="well">Please Select a DJ</p>
</script>
<script src="js/libs/jquery-1.9.1.js"></script>
<script src="js/libs/handlebars-1.0.0.js"></script>
<script src="js/libs/ember-1.0.0.js"></script>
<script src="js/app.js"></script>
</body>
</html>
You are rigth, I try to explain you
Ember has severals ways to go to a Route, here we have two examples.
The linkTo helper, and directly writing the url.
With the linkTo we provide a model to the route, the this keyword
{{#linkTo 'djs.dj' this}}{{name}}{{/linkTo}}
For the url way, ember route needs to know the model to represent, and for this executes the model hook of the route (missing in your example), you can def the dj route like this.
App.DjsDjRoute = Ember.Route.extend({
serialize: function(dj) {
return {
name: dj.name.dasherize()
}
},
model:function(dj){
return App.DJS.find(function(item){
//The url param is the dasherized name
return item.name.dasherize() == dj.name;});
}
});
Also there is a typo defining the routes and this.route('dj', { path: '/djs/:name' }); should be this.route('dj', { path: '/:name' });
Complete JSFiddle http://fiddle.jshell.net/AM7sf/10/show/#/djs

Are Recursive Collections possible in sproutcore2?

I have a customizable navigation tree that can be nested 3 levels deep.
Templates:
<script type="text/x-handlebars" data-template-name="NavItemView">
<a {{bindAttr href="href" class="content.className"}}>{{content.name}}</a>
{{##if content.children}}
another collection here?
{{/if}}
</script>
<script type="text/x-handlebars">
{{collection App.NavItemsCollectionView contentBinding="App.navItemsController" tagName="ul"}}
{{view App.CreateLinkView id="new-link" placeholder="Name"}}
</script>
data:
nav =[
{
"name": "Jethro Larson",
"children":[
{
"name":"Dashboard",
"href": "index.cfm"
}
]
},
{
"name":"Order Management",
"children":
[
{
"name":"OM Reports",
"children":
[
{
"name":"Status Updates",
"href":"index.cfm?blah"
}
]
}
]
}
];
js:
window.App = SC.Application.create();
App.NavItem = SC.Object.extend({
name: null,
href: '#',
});
App.navItemsController = SC.ArrayProxy.create({
content:[],
addMultiple: function(ar){
that = this;
$.each(ar,function(i,item){
that.pushObject(App.NavItem.create(item));
});
}
});
App.NavItemView = SC.View.extend({
tagName:'li'
,templateName: 'NavItemView'
});
App.NavItemsCollectionView = SC.CollectionView.extend({
itemViewClass: App.NavItemView
});
App.navItemsController.addMultiple(nav);
Is there a way to nest collections so I can link the dom to the data structure?
The way you can achieve this is, by putting more logic into your 'NavItemView' template, just include another collection-view at the place you've written "another collection here".
If you've tried that before it might have not worked because of the double hash-char in your if-statement. I've used this already with ten nested levels in a hierarchical progress view. Try
<script type="text/x-handlebars" data-template-name="NavItemView">
<a {{bindAttr href="href" class="content.className"}}>{{content.name}}</a>
{{#if content.children}}
{{view App.NavItemsCollectionView contentBinding="content.children"}}
{{/if}}
</script>
<script type="text/x-handlebars">
{{view App.NavItemsCollectionView contentBinding="App.navItemsController" tagName="ul"}}
{{view App.CreateLinkView id="new-link" placeholder="Name"}}
</script>
as handlebars template.

Categories