V-model error in components (VueJS) - javascript

i'm new on VueJS and i'm making a chat following a tutorial.
in the tutorial, the professor puts a v-model in a component. When I do this, the component is not "rendered" on the screen, and the console responds to "text is not defined," I can not find this problem anywhere, if someone can help me, I'll be grateful, follow my html and js.
HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Chat JS</title>
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<div class="container">
<div class="row">
<div id="app">
<router-link to="/chat">Vá para o Chat</router-link><br>
<router-link to="/rooms">Vá para as Salas</router-link><br><br><br>
<router-view></router-view>
</div>
</div>
</div>
<script src="https://www.gstatic.com/firebasejs/3.5.2/firebase.js"></script>
<script type="text/javascript" src="node_modules/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script type="text/javascript" src="node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript" src="node_modules/vue-router/dist/vue-router.min.js"></script>
<script type="text/javascript" src="node_modules/vuefire/dist/vuefire.min.js"></script>
<script type="text/javascript" src="app/app.js"></script>
</body>
</html>
JS
var firebaseApp = firebase.initializeApp(config);
var db = firebaseApp.database();
const chatComponent = {
template: `
<div class="panel panel-primary">
<div class="panel-heading">Chat</div>
<div class="panel-body" style="height: 400px; overflow-y: scroll;">
<ul class="chat list-unstyled">
<li class="clearfix"
v-bind:class="{left: !isUser(o.email), right: isUser(o.email)}" v-for="o in chat.messages">
<span v-bind:class="{'pull-left': !isUser(o.email), 'pull-right': isUser(o.email)}">
<img v-bind:src="o.photo" class="img-circle"/>
</span>
<div class="chat-body">
<strong>{{o.name}}</strong>
<p>
{{ o.text }}
</p>
</div>
</li>
</ul>
</div>
<div class="panel-footer">
<div class="input-group">
<input type="text" class="form-control input-md" placeholder="Digite sua Mensagem..."/>
<span class="input-group-btn">
<button class="btn btn-sucess btn-md">Enviar</button>
</span>
</div>
</div>
</div>
`,
data: function() {
return {
user: {
email: 'jose#gmail.com',
name: 'Jose Joao',
},
chat: {
messages: [
{
email: "fulano#gmail.com",
text: "Olá eu sou o Fulano",
name: "Fulano",
photo: "http://placehold.it/50/000FFF/fff&text=00"
},
{
email: "jose#gmail.com",
text: "Estou Joia, eu sou o Robo",
name: "Robo",
photo: "http://placehold.it/50/FFFFFF/fff&text=EU"
},
{
email: "jose#gmail.com",
text: "Tudo bem com voce",
name: "Robo",
photo: "http://placehold.it/50/FFFFFF/fff&text=EU"
}
]
}
};
},
methods:{
isUser:function(email){
return this.user.email == email;
}
}
};
const RoomsComponent = {
template:`
<div class="col-md-12" >
<div class="col-md-4" v-for="o in rooms">
<div class="panel panel-primary">
<div class="panel-heading">
{{ o.name }}
</div>
<div class="panel-body">
{{o.description}}<br>
Entrar
</div>
</div>
</div>
<div class="col-md-4">
<input type="text" id="problem"/>
<ul>
</ul>
</div>
</div>
`,
firebase:{
array: db.ref('array')
},
data: function() {
return {
rooms: [
{id: "001", name: "Duvidas", description: "Duvidas Gerais"},
{id: "002",name: "Cadastros/Login", description: "Duvidas sobre Acesso"},
{id: "003",name: "Planos", description: "Duvidas sobre os Planos"},
{id: "004",name: "Creditos", description: "Duvidas sobre os Creditos"},
{id: "005",name: "Modelos", description: "Duvidas sobre os Modelos"},
{id: "006",name: "Envios", description: "Duvidas sobre os Envios"}
]
};
},
methods:{
goToChat: function(room){
router.push('/chat/'+room.id)
},
insertData: function(){
this.$firebaseRefs.array.push({
text: this.text
});
}
}
};
const routes =[
{ path: '/chat/:room', component: chatComponent },
{ path: '/rooms', component: RoomsComponent }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
Recalling that the problem is in the input with id "problem" (to facilitate you) Basically as I said, just to put a V-model it of the error, if anyone knows, thank you!

You need to define your components as follows:
Vue.component('chat-component', {
template: `...`,
data: {
// your data
},
methods: {
// your methods
},
// and so on
});
You have only created javascript objects, not Vue components, in your sample code above.
You can also check the jsFiddle examples from previous questions on vue.js in stackoverflow, which will guide you on the syntax for creating Vue components, parent-child communication, etc.

Related

How to pass Books array length to the parent component from child component in vue.js?

I am developing one page which is responsible from displaying books and the response is coming from backend API, DisplayBooks.vue component is imported inside a Dashboard.vue (parent-component).inside DisplayBooks.vue it contains books [] array , i want to pass this length to the Dashboard.vue component ,How to acheive this thing please help me to fix this thing..
Dashboard.vue
<template>
<div class="main">
<div class="navbar navbar-default navbar-fixed-top">
<div class="navbar-header">
<img src="../assets/education.png" alt="notFound" class="education-image" />
</div>
<ul class="nav navbar-nav">
<li>
<p class="brand">Bookstore</p>
</li>
</ul>
<div class="input-group">
<i #click="handlesubmit();" class="fas fa-search"></i>
<div class="form-outline">
<input type="search" v-model="name" class="form-control" placeholder='search...' />
</div>
</div>
<ul class="nav navbar-nav navbar-right" id="right-bar">
<li><a> <i class="far fa-user"></i></a></li>
<p class="profile-content">profile</p>
<li #click="shownComponent='Cart'"><a><i class="fas fa-cart-plus"></i></a></li>
<p class="cart-content" >cart <span class="length" v-if="booksCount">{{booksCount}}</span></p>
</ul>
</div>
<div class="mid-body">
<!-- i want to display books length here -->
<h6>Books<span class="items">({{books.length}})</span></h6>
<select class="options" #change="applyOption">
<option disabled value="">Sort by relevance</option>
<option value="HighToLow">price:High to Low</option>
<option value="LowToHigh">price:Low to High</option>
</select>
</div>
<div v-if="flam==false">
<h2>Hello</h2>
</div>
<DisplayBooks v-show="flag==='noOrder' && shownComponent==='DisplayBooks'" #update-books-count="(n)=>booksCount=n" />
<Cart v-show=" shownComponent==='Cart'" />
<sortBooksLowtoHigh v-show="flag==='lowToHigh'" #update-books-count="(n)=>booksCount=n" />
<sortBooksHightoLow v-show="flag==='highToLow'" #update-books-count="(n)=>booksCount=n" />
</div>
</template>
<script>
import sortBooksLowtoHigh from './sortBooksLowtoHigh.vue'
import sortBooksHightoLow from './sortBooksHightoLow.vue'
import DisplayBooks from './DisplayBooks.vue'
import Cart from './Cart.vue'
export default {
components: {
DisplayBooks,
sortBooksLowtoHigh,
sortBooksHightoLow,
Cart
},
data() {
return {
shownComponent:'DisplayBooks',
booksCount:0,
flag: 'noOrder',
brand: 'Bookstore',
name: '',
flam: true,
visible: true,
}
},
methods: {
flip() {
this.flam = !this.flam;
},
applyOption(evt) {
if (evt.target.value === "HighToLow") {
this.flag = 'highToLow';
} else this.flag = 'lowToHigh';
},
}
}
</script>
DisplayBooks.vue
<template>
<div class="carddisplay-section">
<!-- <div class="mid">
<h6>Books<span class="items">({{books.length}})</span></h6>
</div> -->
<div v-for="book in books" :key="book.id" class="card book" >
<div class="image-section" #mouseover="book.hover = true" #mouseleave="book.hover = false">
<div class="image-container">
<img v-bind:src="book.file" />
</div>
</div>
<div class="title-section" >
{{book.name}}
</div>
<div class="author-section">
by {{book.author}}
</div>
<div class="price-section">
Rs. {{book.price}}<label class="default">(2000)</label>
</div>
<div class="buttons">
<div class="button-groups" v-if="!addedBooks.includes(book.id)">
<button type="submit" #click="handleCart(book.id);toggle(book.id);addedBooks.push(book.id)" class="AddBag">Add to Bag</button>
<button class="wishlist">wishlist</button>
</div>
<div class="AddedBag" v-else>
<button class="big-btn" #click="removeFromCart(book.id);addedBooks=addedBooks.filter(id=>id!==book.id)">Added to Bag</button>
</div>
</div>
<div class="description" v-if="book.hover">
<p class="hovered-heading">BookDetails</p>
{{book.description}}
</div>
</div>
</div>
</template>
<script>
import service from '../service/User'
export default {
mounted() {
service.userDisplayBooks().then(response => {
let data = response.data;
data.map(function(obj) {
obj.hover = false;
return obj;
});
this.books.push(...data);
return response;
})
},
data() {
return {
isActive:true,
result: 0,
authorPrefix: 'by',
pricePrefix: 'Rs.',
defaultStrikePrice: '(2000)',
buttonValue: 'Add to Bag',
buttonWishlist:'wishlist',
buttonAddedBag:'Added to Bag',
flag: true,
state: true,
addedBooks:[],
clickedCard: '',
books: [] // i want to display this array length
}
},
watch:{
addedBooks:{
handler(val){
this.$emit('update-books-count',val.length)
},
deep:true
}
},
methods: {
toggleClass: function(event){
this.isActive = !this.isActive;
return event;
},
toggle(id) {
this.clickedCard = id;
console.log(this.clickedCard);
},
flip() {
this.state = !this.state;
},
Togglebtn() {
this.flag = !this.flag;
},
handleCart(bookId){
let userData={
id: bookId,
}
service.userUpdateCart(userData).then(response=>{
return response;
}).catch(error=>{
alert("error while displaying Books");
return error;
})
},
removeFromCart(bookId){
let userData={
id:bookId,
}
service.userRemoveFromCart(userData).then(response=>{
return response;
}).catch(error=>{
alert("error while removing from cart");
return error;
})
}
}
}
</script>

How to filter posts in Vue with components and v-bind:class

I'm trying to make an example based on this pen I got from here:
https://codepen.io/conradolandia/pen/YzyPmrv
But I want to use vue-router, I've tried this: (pen: https://codepen.io/conradolandia/pen/vYNERPW)
HTML:
<main class="wrap">
<div id="app">
<router-view></router-view>
</div>
</main>
<template id="post-list-template">
<div class="container">
<div class="row">
<h4>Filter by album:</h4>
<div class="filters">
<button class="btn" v-bind:class="{ active: currentFilter === 'ALL' }" v-on:click="setFilter('ALL')">all</button>
<button class="btn" v-bind:class="{ active: currentFilter === 'art' }" v-on:click="setFilter('art')">art</button>
<button class="btn" v-bind:class="{ active: currentFilter === 'doodles' }" v-on:click="setFilter('doodles')">doodles</button>
<button class="btn" v-bind:class="{ active: currentFilter === 'workshops' }" v-on:click="setFilter('workshops')">workshops</button>
</div>
</div>
<div class="columns is-multiline">
<div class="column is-3" v-if="currentFilter === post.category || currentFilter === 'ALL'" v-bind:key="post.title" v-for="post in posts">
<div class="card post">
<img class="card-img-top" v-bind:src="post.image">
<div class="card-body">
<div class="card-title">{{ post.title }}</div>
<small class="tags">{{ post.category }}</small>
</div>
</div> <!-- .post -->
</div> <!-- .col-md-4 -->
</div> <!-- .row -->
</div> <!-- .container -->
</template>
CSS:
body{
background-color: #ccc;
box-sizing:border-box;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
}
.post {
margin-bottom: 20px;
}
.post img{ width: 100%;}
.tags {background-color: #ccc; padding: 3px 5px;}
.filters {
margin-bottom: 20px;
}
JS:
var postList = Vue.extend({
template: "#post-list-template",
data: function(){
return {
currentFilter:'ALL',
posts: [
{title: "Artwork", image: "https://picsum.photos/g/200?image=122", category: 'art'},
{title: "Charcoal", image: "https://picsum.photos/g/200?image=116", category: 'art'},
{title: "Sketching", image: "https://picsum.photos/g/200?image=121", category: 'doodles'},
{title: "Acrillic", image: "https://picsum.photos/g/200?image=133", category: 'workshops'},
{title: "Pencil", image: "https://picsum.photos/g/200?image=134", category: 'doodles'},
{title: "Pen", image: "https://picsum.photos/g/200?image=115", category: 'art'},
{title: "Inking", image: "https://picsum.photos/g/200", category: 'workshops'},
{title: "Artwork", image: "https://picsum.photos/g/200?image=121", category: 'art'},
{title: "Charcoal", image: "https://picsum.photos/g/200?image=115", category: 'art'},
{title: "Sketching", image: "https://picsum.photos/g/200?image=124", category: 'doodles'},
{title: "Acrillic", image: "https://picsum.photos/g/200?image=13", category: 'workshops'},
{title: "Pencil", image: "https://picsum.photos/g/200?image=14", category: 'doodles'},
]
}
},
methods: {
setFilter: function(filter) {
this.currentFilter = filter;
}
},
})
// Start a new instance of router (instead of router.map)
var router = new VueRouter({
routes: [
{ path: '/', component: postList }
]
})
// Start a new instance of the Application required (instead of router.start)
new Vue({
el: '#app',
router: router,
})
So far, no luck. The filter kind of works, the first click I make activates a filtering option, but then all filters stop working, and firefox complains with "TypeError: "e is undefined"".
Can somebody point me in the right direction, please? I don't understand why the first codepen link works but the second doesn't.
Clarifying: When I click any filter, filters kind of work, but if I click the "ALL" filter, everything stops working.
Try using a computed function
computed:{
filteredPosts:function(){
if(this.currentFilter==='ALL'){
return this.posts;
}
return this.posts.filter(post=>{
return post.category === this.currentFilter;
})
}
}
You can use filteredPosts instead of posts while looping
<div class="columns is-multiline">
<div class="column is-3" :key="post.title" v-for="post in filteredPosts">
<div class="card post">
<img class="card-img-top" :src="post.image">
<div class="card-body">
<div class="card-title">{{ post.title }}</div>
<small class="tags">{{ post.category }}</small>
</div>
</div> <!-- .post -->
</div> <!-- .col-md-4 -->
</div> <!-- .row -->
You don't need to use any condition while looping, since the computed function will do the job.

How do I access object values in various elements to display event data?

I am using vue.js to build a events management app. The problem is that I am unable to render the value of each event in the list group to the DOM. It just keeps rendering the curly braces expression to the DOM.
Here is the Js Fiddle :
https://jsfiddle.net/ufy01L3q/2/
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>events Management</title>
</head>
<body>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<script src="https://unpkg.com/vue"></script>
<!-- navigation bar -->
<nav class="navbar navbar-default">
<div class="container-fluid">
<a class="navbar-brand"><i class = ""></i> events Management </a>
</div>
</nav>
<!-- main body of our application -->
<div class="container" id="events">
<!-- add an event form -->
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<h3>Add an Event</h3>
</div>
<div class="panel-body">
<div class="form-group">
<input class="form-control" placeholder="Event Name" v-model="event.name">
</div>
<div class="form-group">
<textarea class="form-control" placeholder="Event Description" v-model="event.description"></textarea>
</div>
<div class="form-group">
<input type="date" class="form-control" placeholder="Date" v-model="event.date">
</div>
<button class="btn btn-primary" v-on="click: addEvent">Submit</button>
</div>
</div>
</div>
<!-- show the events -->
<div class="col-sm-6">
<div class="list-group">
<a href="#" class="list-group-item" v-repeat="event in events">
<h4 class="list-group-item-heading">
<i class="glyphicon glyphicon-bullhorn"></i>
{{ event.name }}
</h4>
<h5>
<i class="glyphicon glyphicon-calendar" v-if="event.date"></i>
{{ event.date }}
</h5>
<p class="list-group-item-text" v-if="event.description">{{ event.description }}</p>
<button class="btn btn-xs btn-danger" v-on="click: deleteEvent($index)">Delete</button>
</a>
</div>
</div>
</div>
// app.js
<script>
new Vue({
// We want to target the div with an id of 'events'
el: '#events',
// Here we can register any values or collections that hold data
// for the application
data: {
event: {
name: '',
description: '',
date: ''
},
events: []
},
// Anything within the ready function will run when the application loads
ready: function() {
// When the application loads, we want to call the method that initializes
// some data
this.fetchEvents();
},
// Methods we want to use in our application are registered here
methods: {
// We dedicate a method to retrieving and setting some data
fetchEvents: function() {
var events = [{
id: 1,
name: 'TIFF',
description: 'Toronto International Film Festival',
date: '2015-09-10'
},
{
id: 2,
name: 'The Martian Premiere',
description: 'The Martian comes to theatres.',
date: '2015-10-02'
},
{
id: 3,
name: 'SXSW',
description: 'Music, film and interactive festival in Austin, TX.',
date: '2016-03-11'
}
];
// $set is a convenience method provided by Vue that is similar to pushing
// data onto an array
this.$set('events', events);
},
// Adds an event to the existing events array
addEvent: function() {
if (this.event.name) {
this.events.push(this.event);
this.event = {
name: '',
description: '',
date: ''
},
}
}
}
});
</script>
</body>
</html>
<!-- JS -->
Thank you in advance for the help.
First: you don't properly include Vue. Include it inside <head>, and in jsfiddle include just a script url, without tags.
Second: your event binding syntax is wrong: you're trying v-on="click: addEvent", but the proper syntax is v-on:click="addEvent($event)" - in this example you also pass $event to your method, and you an extract a value like this: $event.target.value.

Angular JS function not defined error

I am learning AngularJS from AngularJS.org video tutorials but when I run my code it says
Error: [ng:areq] Argument 'ReviewController' is not a function
I got undefined in my console but my code looks the same as in the video here is my html
<!doctype html>
<html ng-app="store">
<title>Testing AngularJS</title>
<head>
<link rel="stylesheet" type="text/css" href="bootstrap.css"/>
<script type="text/javascript" src="js/angular.js"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body ng-controller="StoreController as store">
<ul class="list-group">
<li class="list-group-item" ng-repeat="product in store.products">
<h3>{{product.name}}
<em class="pull-right">{{product.price | currency}}</em>
<img class="gallery" ng-src="{{product.images[0].full}}"/>
</h3>
<section ng-controller="PanelController as panel">
<ul class="nav nav-pills">
<li ng-class="{active: panel.isSelected(1)}"><a href ng-click="panel.selectTab(1)">Description</a></li>
<li ng-class="{active: panel.isSelected(2)}"><a href ng-click="panel.selectTab(2)">Specifications</a>
</li>
<li ng-class="{active: panel.isSelected(3)}"><a href ng-click="panel.selectTab(3)">Reviews</a></li>
</ul>
<div class="panel" ng-show="panel.isSelected(1)">
<h3> Description</h3>
<h4>{{product.description}}</h4>
</div>
<div class="panel" ng-show="panel.isSelected(2)">
<h3> Specifications</h3>
<blockquote>None yet</blockquote>
</div>
<div class="panel" ng-show="panel.isSelected(3)">
<h3> Reviews</h3>
<blockquote ng-repeat="review in product.reviews">
<b>Stars: {{review.stars}}</b>
<p>{{review.body}}</p>
<cite>_{{review.author}}</cite>
</blockquote>
<form name="reviewForm" ng-controller="ReviewController as reviewCtrl">
<blockquote>
<b>Stars: {{reviewCtrl.review.stars}}</b>
<p>{{reviewCtrl.review.body}}</p>
<cite>_{{reviewCtrl.review.author}}</cite>
</blockquote>
<label for="select">Select</label>
<select id="select" ng-model="reviewCtrl.review.stars">
<option value="1">1 star</option>
<option value="2">2 star</option>
<option value="3">3 star</option>
</select>
<label for="comments"></label>
<textarea id="comments" ng-model="reviewCtrl.review.body"></textarea>
<label for="email">Email</label>
<input ng-model="reviewCtrl.review.author" type="email" id="email"/>
<input type="submit" value="Submit"/>
</form>
</div>
</section>
</li>
</ul>
</body>
</html>
Here is my app.js file
(function () {
var app = angular.module('store', []);
app.controller('StoreController', function () {
this.products = [
{
name: 'Cup',
price: 2.95,
description: 'It is the best Buy it fast',
images: [
{
full: 'gem.jpeg'
}
],
reviews: [
{
stars: 5,
body: 'This is the best gem',
author: 'dadsa#dasasd.com'
},
{
stars: 1,
body: 'easily broken',
author: 'zzzfasdaadsa#dasasd.com'
}
]
},
{
name: 'Bottle',
price: 1.12,
description: 'It\'s the best bottle',
images: [
{
full: 'gem.jpeg'
}
],
reviews: [
{
stars: 2,
body: 'Latest gem',
author: 'aasdsa#dasasd.com'
}
]
}
]; // product is the property of the controller
});
app.controller("ReviewController", function () {
this.review = {};
});
app.controller("PanelController", function () {
this.tab = 1;
this.selectTab = function (setTab) {
this.tab = setTab;
};
this.isSelected = function (checkTab) {
return this.tab === checkTab;
};
});
})();
The problem is here:
<script type="text/javascript" src="js/angular.js"></script>
<script type="text/javascript" src="app.js"></script>
Scripts are executed in the order that they are encountered on the page. So angular.js runs before app.js. It will parse the document and try to resolve ng-app (and thereby ng-controller) before app.js has a chance to execute.
There are two easy ways to solve this:
Put app.js inline at the end of your document
Although I did say that scripts are executed in the order they are encountered, angularjs puts its initialization code behind document.isready. It's loaded, so you will have access to angular.module, but it won't execute its bootstrap logic until after your own code has finished loading. This solution is fine for tiny projects, but isn't great when your code grows large.
Bootstrap your application manually
Remove the ng-app="store" from your html code, and at the end of app.js, you will add the following code
angular.element(document).ready(function() {
angular.bootstrap(document, ['store']);
});`
If you work with angular long enough, you will get very used to this second solution, as it helps us play nicely with dynamic loaders such as $script, RequireJS, et al -- not to mention the very example you've posted!

codeschool ember js 5.3

I have been going through the emberjs course on codeschool and I came across this interesting problem. In 5.3, the question I am stuck on is:
Provide a model for the ContactsIndex Route which will provide just
one model – the contact for Anostagia. You can look this contact up by
ID.
No matter what I try it will not accept this app.js file?
I am nearly 90% sure I have this setup correctly... any thoughts?
var App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Router.map(function() {
this.route('credits', { path: '/thanks' });
this.resource('products', function() {
this.resource('product', { path: '/:product_id' });
});
this.resource('contacts', function() {
this.resource('contact', { path: '/:contact_id' });
});
});
App.IndexController = Ember.ArrayController.extend({
productsCount: Ember.computed.alias('length'),
logo: 'images/logo-small.png',
time: function() {
return (new Date()).toDateString();
}.property()
});
App.ContactsIndexController = Ember.ObjectController.extend({
contactName: Ember.computed.alias('name'),
avatar: 'images/avatar.png',
open: function() {
return ((new Date()).getDay() === 0) ? "Closed" : "Open";
}.property()
});
App.ProductsController = Ember.ArrayController.extend({
sortProperties: ['title']
});
App.ContactsController = Ember.ArrayController.extend({
sortProperties: ['name']
});
App.ContactsIndexRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('contact', params.contact_id);
}
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.findAll('contact');
}
});
App.ProductsRoute = Ember.Route.extend({
model: function() {
return this.store.findAll('product');
}
});
App.ContactsRoute = Ember.Route.extend({
model: function() {
return this.store.findAll('contact');
}
});
App.IndexRoute = Ember.Route.extend({
model: function(){
return this.store.findAll('product');
}
});
App.ApplicationAdapter = DS.FixtureAdapter.extend();
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 }),
crafter: DS.belongsTo('contact', { async: true })
});
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.',
isOnSale: true,
image: 'images/products/flint.png',
reviews: [100,101],
crafter: 200
},
{
id: 2,
title: 'Kindling',
price: 249,
description: 'Easily combustible small sticks or twigs used for starting a fire.',
isOnSale: false,
image: 'images/products/kindling.png',
reviews: [],
crafter: 201
},
{
id: 3,
title: 'Matches',
price: 499,
description: 'One end is coated with a material that can be ignited by frictional heat generated by striking the match against a suitable surface.',
isOnSale: true,
reviews: [103],
image: 'images/products/matches.png',
crafter: 201
},
{
id: 4,
title: 'Bow Drill',
price: 999,
description: 'The bow drill is an ancient tool. While it was usually used to make fire, it was also used for primitive woodworking and dentistry.',
isOnSale: false,
reviews: [104],
image: 'images/products/bow-drill.png',
crafter: 200
},
{
id: 5,
title: 'Tinder',
price: 499,
description: 'Tinder is easily combustible material used to ignite fires by rudimentary methods.',
isOnSale: true,
reviews: [],
image: 'images/products/tinder.png',
crafter: 201
},
{
id: 6,
title: 'Birch Bark Shaving',
price: 999,
description: 'Fresh and easily combustable',
isOnSale: true,
reviews: [],
image: 'images/products/birch.png',
crafter: 200
}
];
App.Contact = DS.Model.extend({
name: DS.attr('string'),
about: DS.attr('string'),
avatar: DS.attr('string'),
products: DS.hasMany('product', { async: true })
});
App.Contact.FIXTURES = [
{
id: 200,
name: 'Giamia',
about: 'Although Giamia came from a humble spark of lightning, he quickly grew to be a great craftsman, providing all the warming instruments needed by those close to him.',
avatar: 'images/contacts/giamia.png',
products: [1]
},
{
id: 201,
name: 'Anostagia',
about: 'Knowing there was a need for it, Anostagia drew on her experience and spearheaded the Flint & Flame storefront. In addition to coding the site, she also creates a few products available in the store.',
avatar: 'images/contacts/anostagia.png',
products: [2]
}
];
App.Review = DS.Model.extend({
text: DS.attr('string'),
reviewedAt: DS.attr('date'),
product: DS.belongsTo('product')
});
App.Review.FIXTURES = [
{
id: 100,
text: "Started a fire in no time!"
},
{
id: 101,
text: "Not the brightest flame, but warm!"
}
];
The index.html file (if needed):
<!DOCTYPE html>
<html>
<head>
<base href='http://courseware.codeschool.com/ember/' />
<link href='bootstrap.css' rel='stylesheet' />
<link href='application.css' rel='stylesheet' />
<script src='jquery.js'></script>
<script src='handlebars.js'></script>
<script src='ember.js'></script>
<script src='ember-data.js'></script>
<script src='app.js'></script>
</head>
<body>
<script type='text/x-handlebars' data-template-name='application'>
<div class='navbar navbar-default'>
<div class='container'>
{{#link-to 'index' class='navbar-brand'}}<img src='images/logo.png' alt='logo' height='34' width='224' />{{/link-to}}
<ul class='nav navbar-nav navbar-right'>
{{#link-to 'index' tagName='li'}}Home{{/link-to}}
{{#link-to 'products' tagName='li'}}Products{{/link-to}}
{{#link-to 'contacts' tagName='li'}}Contacts{{/link-to}}
</ul>
</div>
</div>
<div class="container">
{{outlet}}
</div>
<footer class='container'>
<hr />
<p class='pull-left'>© 2013 The Flint & Flame</p>
<p class='pull-right'>{{#link-to 'credits'}}Credits{{/link-to}}</p>
</footer>
</script>
<script type='text/x-handlebars' data-template-name='index'>
<div class="jumbotron">
<h1>Welcome to The Flint & Flame!</h1>
<p class="tagline">
<img {{bind-attr src='logo'}} alt='Logo' />
Everything you need to make it through the winter.
</p>
<p>
{{#link-to 'products' class='btn btn-primary btn-lg'}}
Browse All {{productsCount}} Items »
{{/link-to}}
</p>
</div>
<p class='pull-right text-muted'>Rendered on {{time}}</p>
</script>
<script type='text/x-handlebars' data-template-name='contacts/index'>
<div class='row'>
<img {{bind-attr src='avatar'}} alt='Avatar' class='img-thumbnail col-sm-4'/>
<div class='col-sm-8'>
<h1>About The Fire Sprites</h1>
<p>Contact {{contactName}} for more info!</p>
<p>Current Status: {{open}}.</p>
</div>
</div>
</script>
<script type='text/x-handlebars' data-template-name='credits'>
<h1>Thanks for the Help!</h1>
<p>This site would not be possible without the hardworking Ember Core Team!</p>
</script>
<script type="text/x-handlebars" data-template-name='products'>
<div class='row'>
<div class='col-sm-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-sm-7'>
<h2>{{title}}</h2>
<h3 class="text-success">${{price}}</h3>
<p class="text-muted">{{description}}</p>
<p>Finely crafted by {{#link-to 'contact' crafter}}{{crafter.name}}{{/link-to}}.</p>
<h3>Reviews</h3>
<ul>
{{#each reviews}}
<li><p>{{text}}</p></li>
{{else}}
<li><p class='text-muted'><em>No reviews yet. Be the first to write one!</em></p></li>
{{/each}}
</ul>
</div>
<div class='col-sm-5'>
<img {{bind-attr src='image'}} class='img-thumbnail img-rounded'/>
</div>
</div>
</script>
<script type='text/x-handlebars' data-template-name='products/index'>
<p class='text-muted'>Choose a product from those on the left!</p>
</script>
<script type="text/x-handlebars" data-template-name='contacts'>
<div class='row'>
<div class='col-sm-9'>
{{outlet}}
</div>
<div class='col-sm-3'>
<div class='list-group'>
{{#each}}
{{#link-to 'contact' this classNames='list-group-item'}}
{{name}}
{{/link-to}}
{{/each}}
</div>
</div>
</div>
</script>
<script type='text/x-handlebars' data-template-name='contact'>
<div class='row'>
<div class='col-sm-5'>
<img {{bind-attr src='avatar' alt='name'}} class='img-thumbnail img-rounded'/>
</div>
<div class='col-sm-7'>
<h2>{{name}}</h2>
<p>{{about}}</p>
<h3>Products</h3>
<ul>
{{#each products}}
<li>{{#link-to 'product' this}}{{title}}{{/link-to}}</li>
{{/each}}
</ul>
</div>
</div>
</script>
</body>
</html>
It looks like I was being too robust for this question. The answer was the following adjustment:
App.ContactsIndexRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('contact', 201);
}
});

Categories

Resources