codeschool emberjs 7.4 rating a product not working - javascript

I have been battling the level 7.4 review question with no luck:
Rating isn’t a object like Review was, so our createRating function will be a little different. We can addObject the currently selected rating to the array of ratings on our product. You’ll need to save the product to update it in the store.
I can not seem to get the value from the select list. Can anyone point me in the right direction or collaborate on this?
My handlebars code:
<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 class='text-muted'>This Product has a {{rating}} star rating!</p>
<p>Finely crafted by {{#link-to 'contact' crafter}}{{crafter.name}}{{/link-to}}.</p>
{{render 'reviews' reviews}}
<div class='new-rating'>
<h3>Rate {{title}}</h3>
</div>
<div class='new-review'>
<h3>Review {{title}}</h3>
{{#if text}}
<p class='text-muted'>{{text}}</p>
{{/if}}
{{textarea valueBinding='text'}}
<button {{action 'createReview'}} class='btn-primary'>Review</button>
</div>
</div>
<div class='col-sm-5'>
<img {{bind-attr src='image'}} class='img-thumbnail img-rounded'/>
</div>
</div>
{{contact-details contact=crafter className='row'}}
{{view Ember.Select content=ratings value=selectedRating}}
<button {{action 'createRating'}} class='btn-primary'>Rating</button>
</script>
My js code:
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.route('onsale');
this.route('deals');
});
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(),
onSale: function() {
return this.filterBy('isOnSale').slice(0,3);
}.property('#each.isOnSale')
});
App.ContactsIndexController = Ember.Controller.extend({
contactName: 'Anostagia',
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'],
contactsCount: Ember.computed.alias('length')
});
App.ReviewsController = Ember.ArrayController.extend({
sortProperties: ['reviewedAt'],
sortAscending: false
});
App.ContactProductsController = Ember.ArrayController.extend({
sortProperties: ['title']
});
App.ProductController = Ember.ObjectController.extend({
text: '',
ratings: [1,2,3,4,5],
selectedRating: 5,
actions: {
createReview: function(){
var review = this.store.createRecord('review', {
text: this.get('text'),
product: this.get('model'),
reviewedAt: new Date()
});
var controller = this;
review.save().then(function() {
controller.set('text', '');
controller.get('model.reviews').addObject(review);
});
},
createRating: function(){
var rating = this.store.createRecord('rating', {
rating: this.get('selectedRating.value'),
product: this.get('model'),
reviewedAt: new Date()
});
var controller = this;
rating.save().then(function() {
controller.get('model.rating').addObject(rating);
});
}
}
});
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.ProductsIndexRoute = Ember.Route.extend({
model: function(){
return this.store.findAll('product');
}
});
App.ProductsOnsaleRoute = Ember.Route.extend({
model: function(){
return this.modelFor('products').filterBy('isOnSale');
}
});
App.ProductsDealsRoute = Ember.Route.extend({
model: function(){
return this.modelFor('products').filter(function(product){
return product.get('price') < 500;
});
}
});
App.ProductDetailsComponent = Ember.Component.extend({
reviewsCount: Ember.computed.alias('product.reviews.length'),
hasReviews: function(){
return this.get('reviewsCount') > 0;
}.property('reviewsCount')
});
App.ContactDetailsComponent = Ember.Component.extend({
productsCount: Ember.computed.alias('contact.products.length'),
isProductive: function() {
return this.get('productsCount') > 3;
}.property('productsCount')
});
App.ProductView = Ember.View.extend({
isOnSale: Ember.computed.alias('controller.isOnSale'),
classNameBindings: ['isOnSale']
});
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 }),
ratings: DS.attr(),
rating: function(){
return this.get('ratings').reduce(function(previousValue, rating) {
return previousValue + rating;
}, 0) / this.get('ratings').length;
}.property('ratings.#each')
});
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,
ratings: [2,1,3,3]
},
{
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,
ratings: [2,1,3,3]
},
{
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: [],
image: 'images/products/matches.png',
crafter: 201,
ratings: [2,1,3,3]
},
{
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: [],
image: 'images/products/bow-drill.png',
crafter: 200,
ratings: [1,3,3]
},
{
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,
ratings: [2,1,3]
},
{
id: 6,
title: 'Birch Bark Shaving',
price: 999,
description: 'Fresh and easily combustable',
isOnSale: true,
reviews: [],
image: 'images/products/birch.png',
crafter: 201,
ratings: [2,3,5]
}
];
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,4]
},
{
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,3,5,6]
}
];
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!"
}
];

After detailed research, the answer turned out being:
createRating: function() {
var prod = this.get('model');
var ratings = this.get('model.ratings');
ratings.addObject(this.selectedRating);
prod.save();
}

In the code shown, you should be getting the rating using this.get('selectedRating') not this.get('selectedRating.value')
http://emberjs.jsbin.com/xohidixe/1/edit

Related

Angular JS object not found

I have an object in Angular that is being used in the library I'm using. When I wrote a new function I cannot pass this same object. I'm not sure why.
The object is called person. It's bound directly in the HTML. The object returns just 2 items from the cardsCollection array below.
The function I'm trying to write is called clickLike. I literally just want the same thing to happen whether someone clicks or swipes right. You can see the dev site here:
http://430designs.com/xperience/black-label-app/deck.php
Here's the entire controller.js file:
angular.module('black-label', ['ngTouch', 'ngSwippy'])
.controller('MainController', function($scope, $timeout, $window) {
$scope.cardsCollection = [
{
thumbnail: 'images/deck/thor_01.jpg',
collection: 'thoroughbred',
}, {
thumbnail: 'images/deck/thor_02.jpg',
collection: 'thoroughbred',
}, {
thumbnail: 'images/deck/thor_03.jpg',
collection: 'thoroughbred',
}, {
thumbnail: 'images/deck/thor_04.jpg',
collection: 'thoroughbred',
}, {
thumbnail: 'images/deck/thor_05.jpg',
collection: 'thoroughbred',
}, {
thumbnail: 'images/deck/thor_06.jpg',
collection: 'thoroughbred',
}, {
thumbnail: 'images/deck/rhap_01.jpg',
collection: 'rhapsody',
}, {
thumbnail: 'images/deck/rhap_02.jpg',
collection: 'rhapsody',
}, {
thumbnail: 'images/deck/rhap_03.jpg',
collection: 'rhapsody',
}, {
thumbnail: 'images/deck/rhap_04.jpg',
collection: 'rhapsody',
}, {
thumbnail: 'images/deck/rhap_05.jpg',
collection: 'rhapsody',
}, {
thumbnail: 'images/deck/rhap_06.jpg',
collection: 'rhapsody',
}, {
thumbnail: 'images/deck/cha_01.jpg',
collection: 'chalet',
}, {
thumbnail: 'images/deck/cha_02.jpg',
collection: 'chalet',
}, {
thumbnail: 'images/deck/cha_03.jpg',
collection: 'chalet',
}, {
thumbnail: 'images/deck/cha_04.jpg',
collection: 'chalet',
}, {
thumbnail: 'images/deck/cha_05.jpg',
collection: 'chalet',
}, {
thumbnail: 'images/deck/cha_06.jpg',
collection: 'chalet',
}, {
thumbnail: 'images/deck/mod_01.jpg',
collection: 'modern',
}, {
thumbnail: 'images/deck/mod_02.jpg',
collection: 'modern',
}, {
thumbnail: 'images/deck/mod_03.jpg',
collection: 'modern',
}, {
thumbnail: 'images/deck/mod_04.jpg',
collection: 'modern',
}, {
thumbnail: 'images/deck/mod_05.jpg',
collection: 'modern',
}, {
thumbnail: 'images/deck/mod_06.jpg',
collection: 'modern',
}, {
thumbnail: 'images/deck/ind_01.jpg',
collection: 'indulgence',
}, {
thumbnail: 'images/deck/ind_02.jpg',
collection: 'indulgence',
}, {
thumbnail: 'images/deck/ind_03.jpg',
collection: 'indulgence',
}, {
thumbnail: 'images/deck/ind_04.jpg',
collection: 'indulgence',
}, {
thumbnail: 'images/deck/ind_05.jpg',
collection: 'indulgence',
}, {
thumbnail: 'images/deck/ind_06.jpg',
collection: 'indulgence',
}, {
thumbnail: 'images/deck/cnt_01.jpg',
collection: 'center-stage',
}, {
thumbnail: 'images/deck/cnt_02.jpg',
collection: 'center-stage',
}, {
thumbnail: 'images/deck/cnt_03.jpg',
collection: 'center-stage',
}, {
thumbnail: 'images/deck/cnt_04.jpg',
collection: 'center-stage',
}, {
thumbnail: 'images/deck/cnt_05.jpg',
collection: 'center-stage',
}, {
thumbnail: 'images/deck/cnt_06.jpg',
collection: 'center-stage',
}, {
thumbnail: 'images/deck/vin_01.jpg',
collection: 'vineyard',
}, {
thumbnail: 'images/deck/vin_02.jpg',
collection: 'vineyard',
}, {
thumbnail: 'images/deck/vin_03.jpg',
collection: 'vineyard',
}, {
thumbnail: 'images/deck/vin_04.jpg',
collection: 'vineyard',
}, {
thumbnail: 'images/deck/vin_05.jpg',
collection: 'vineyard',
}, {
thumbnail: 'images/deck/vin_06.jpg',
collection: 'vineyard',
},
];
// Do the shuffle
var shuffleArray = function(array) {
var m = array.length,
t, i;
// While there remain elements to shuffle
while (m) {
// Pick a remaining element
i = Math.floor(Math.random() * m--);
// And swap it with the current element.
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
};
$scope.deck = shuffleArray($scope.cardsCollection);
$scope.myCustomFunction = function() {
$timeout(function() {
$scope.clickedTimes = $scope.clickedTimes + 1;
$scope.actions.unshift({ name: 'Click on item' });
});
};
$scope.count = 0;
$scope.showinfo = false;
$scope.clickedTimes = 0;
$scope.actions = [];
$scope.picks = [];
var counterRight = 0;
var counterLeft = 0;
$scope.swipeend = function() {
$scope.actions.unshift({ name: 'Collection Empty' });
$window.location.href = 'theme-default.html';
}; //endswipeend
$scope.swipeLeft = function(person) {
//Essentially do nothing
$scope.actions.unshift({ name: 'Left swipe' });
$('.circle.x').addClass('dislike');
$('.circle.x').removeClass('dislike');
$(this).each(function() {
return counterLeft++;
});
}; //end swipeLeft
$scope.swipeRight = function(person) {
$scope.actions.unshift({ name: 'Right swipe' });
// Count the number of right swipes
$(this).each(function() {
return counterRight++;
});
// Checking the circles
$('.circle').each(function() {
if (!$(this).hasClass('checked')) {
$(this).addClass('checked');
return false;
}
});
$('.icon-like').addClass('liked');
$('.icon-like').removeClass('liked');
$scope.picks.push(person.collection);
// console.log('Picks: ' + $scope.picks);
// console.log("Counter: " + counterRight);
if (counterRight === 4) {
// Calculate and store the frequency of each swipe
var frequency = $scope.picks.reduce(function(frequency, swipe) {
var sofar = frequency[swipe];
if (!sofar) {
frequency[swipe] = 1;
} else {
frequency[swipe] = frequency[swipe] + 1;
}
return frequency;
}, {});
var max = Math.max.apply(null, Object.values(frequency)); // most frequent
// find key for the most frequent value
var winner = Object.keys(frequency).find(element => frequency[element] == max);
$window.location.href = 'theme-' + winner + '.html';
} //end 4 swipes
}; //end swipeRight
$scope.clickLike = function() {
$scope.swipeRight();
}; //clickLike
});
HTML file for the deck
<div class="ng-swippy noselect">
<div person="person" swipe-directive="swipe-directive" ng-repeat="person in peopleToShow" class="content-wrapper swipable-card">
<div class="card">
<div style="background: url({{person.thumbnail}}) no-repeat 50% 15%" class="photo-item"></div>
<div class="know-label">{{labelOk ? labelOk : "YES"}}</div>
<div class="dontknow-label">{{labelNegative ? labelNegative : "NO"}}</div>
</div>
<div class="progress-stats" ng-if="data">
<div class="card-shown">
<div class="card-shown-text">{{person.collection}}</div>
<div class="card-shown-number">{{person.subtitle}}</div>
</div>
<div class="card-number">{{collection.length - (collection.indexOf(person))}}/{{collection.length}}
</div>
</div>
<div class="container like-dislike" >
<div class="circle x" ng-click="$parent.$parent.clickDisike()"></div>
<div class="icon-like" ng-click="$parent.$parent.clickLike()"></div>
<div class="clearfix"></div>
</div>
</div><!-- end person-->
<div class="clearfix"></div>
If I'm leaving anything out please let me know.
Thanks in advance everyone!
I don't see how you get peopleToShow:
ng-repeat="person in peopleToShow"
Possibly you want to replace it with:
ng-repeat="person in cardsCollection"
because $scope.cardsCollection seems is where you store your thumbnails.

Ember Data Polymorphic Relationship: Not Using Correct Model

Using an older version of ember(1.7.1) and ember-data(1.0.0 beta 12) as trying to upgrade to 2.0. When loading my application I get the following warning:
WARNING: The payload for 'App.QPAC' contains these unknown keys: [abs_parent_gbid,author,comments,course,follows,has_more_comments,is_announcement,more_comments_count,resource_uri,title]. Make sure they've been defined in your model.
Here is my model code (There are other models than post but they aren't being loaded in this instance).
App.Feedstory = DS.Model.extend({
global_id: DS.attr('string'),
story_type: DS.attr('string'),
story: DS.belongsTo('qPAC', {polymorphic: true}),
});
App.QPAC = DS.Model.extend({
global_id: DS.attr('string'),
global_code: DS.attr('string'),
body: DS.attr('string'),
});
App.Post = App.QPAC.extend({
title: DS.attr('string'),
is_announcement: DS.attr('boolean'),
author: DS.belongsTo('user'),
comments: DS.hasMany('comment'),
});
Ember inspector is showing me that the all the feedstory objects of type Post are being found and it shows in the Post attributes that the correct IDs are being loaded but not the other attributes.
The warning says it's looking for the post attributes in the App.QPAC model and not App.Post. Any ideas?
Edit: Added serializers and adapters
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api/v2'
});
App.FeedstorySerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
primaryKey: 'global_id',
attrs: {
pin: {embedded: 'always' },
story: {embedded: 'always'},
},
});
App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
primaryKey: 'global_id',
attrs: {
author: {embedded: 'always' },
course: {embedded: 'always' },
pin: {embedded: 'always' },
comments: {embedded: 'always'},
follows: {embedded: 'always'},
},
normalize: function(type, hash, prop) {
if (Object.keys(hash.comments).length === 0) {
hash.comments = null;
}
if (Object.keys(hash.follows).length === 0) {
hash.follows = null;
}
return this._super(type, hash, prop);
},
});

Error while processing route: todos undefined is not a function

I'm getting this error after the Displaying Model Data step while trying to follow the TodoMVC demo app on the Ember site (http://guides.emberjs.com/v1.10.0/getting-started/). My javascript code up to this point is:
window.Todos = Ember.Application.create();
Todos.ApplicationAdapter = DS.FixtureAdapter.extend();
Todos.Router.map(function () {
this.resource('todos', { path: '/' });
});
Todos.TodosRoute = Ember.Route.extend({
model: function () {
return this.store.find('todo');
}
});
Todos.Todo = DS.Model.extend({
title: DS.attr('string'),
isCompleted: DS.attr('boolean')
});
Todos.Todo.FIXTURES = [
{
id: 1,
title: 'Learn Ember.js',
isCompleted: true
},
{
id: 2,
title: '...',
isCompleted: false
},
{
id: 3,
title: 'Profit!',
isCompleted: false
}
];
I think your router.map is wrong. Try using it in this way -
Todos.Router.map(
function () {
this.resource('todos', { path: '/' }, function () {
this.route('active');
this.route('completed');
});
});

How to show immediately a property of an associated model after creation?

If I create a new movie object, the associated username from owner (App.User) isn't shown. It shows only after I reload the page. Any idea how I can achieve to show immediately the associated username after I have created a new movie?
Code so far:
App.Movie = Ember.Model.extend({
objectId: Ember.attr(),
title: Ember.attr(),
year: Ember.attr(),
owner: Ember.belongsTo('App.User', {
key: 'owner',
serializer: UserType
})
});
App.User = Ember.Model.extend({
objectId: Ember.attr(),
username: Ember.attr(),
});
App.Movie.adapter = Ember.Adapter.create({
createRecord: function(record) {
return Ember.$.ajax({
headers: {
'X-Parse-Application-Id': '',
'X-Parse-REST-API-Key': ''
},
type: 'POST',
url: 'https://api.parse.com/1/classes/Movie',
contentType: 'application/json',
data: JSON.stringify(record)
}).then(function(data) {
record.load(data.objectId, record.get('_data'));
record.didCreateRecord();
});
}
});
{{#each movie in this}}
<tr>
<td>{{movie.year}}</td>
<td>{{movie.title}}</td>
<td>{{movie.owner.username}}</td>
</tr>
{{/each}}
App.MoviesIndexController = Ember.ArrayController.extend({
rawDescription: '',
year: '',
title: '',
errors: null,
actions: {
createMovie: function () {
var rawDescription = this.get('rawDescription');
if (!rawDescription.match(/([^$]+)(\d{4})/)) {
this.set('errors', {
rawDescription: 'Oh snap! Please include the movie\'s title and year.'
});
} else if (!this.isUnique({
rawDescription: rawDescription
})) {
this.set('errors', {
rawDescription: 'Oh snap! The movie already exists.'
});
} else {
var rv = this.parseRawDescription(this.get('rawDescription')),
title = rv[1],
year = rv[2],
newMovie = App.Movie.create({
owner: App.Session.authUser,
ratings: [{ objectId: App.Session.objectId, value: 0 }]
title: title,
watched: false,
year: year,
});
newMovie.save();
this.setProperties({ rawDescription: '', errors: null });
}
}
}
});
I'm showing it as working, are you sure App.Session.authUser is populated? if you try console.log(newMovie.get('owner.username')) after you create it does it show anything?
http://emberjs.jsbin.com/AYidAdi/1/edit

Ember Data - Assign a value inside an object

I'm starting up with ember and trying to get some data from an Api and assign it to an Emberjs model.
My api returns something like:
[
{
email: 'someemail#domain.com'
name: {
firstname: 'first name',
lastname: 'last name'
}
}
{
email: 'someemail2#domain.com'
name: {
firstname: 'another first name',
lastname: 'another last name'
}
},
{
email: 'someemail3#domain.com'
name: undefined
}
]
And my code is:
App.Store = DS.Store.extend({
revision: 12,
});
App.Store.registerAdapter('App.Users', DS.Adapter.extend({
findAll: function(store, type, id) {
$.getJSON('https://domain.com/users?callback=?', {
'auth_token': token
}).done(function(json){
store.loadMany(type, json);
});
},
}));
App.Store.registerAdapter('App.Users', DS.Adapter.extend({
findAll: function(store, type, id) {
$.getJSON('https://domain.com/users?callback=?', {
'auth_token': token
}).done(function(json){
store.loadMany(type, json);
});
},
}));
App.Router.map(function() {
this.route("users", { path: "/users" });
});
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.Users.find();
}
});
App.Users = DS.Model.extend({
email: DS.attr('string'),
firstname: DS.attr('string'),
didLoad: function() {
console.log('model loaded', this.toJSON());
}
});
<script type="text/x-handlebars" data-template-name="users">
{{#each model}}
{{email}} - {{firstname}}
{{/each}}
</script>
Obviously firstname is empty for every object in the array.
Does anyone know what's the proper way to do this?
Thanks
Have you tried setting up your User model like this:
App.Adapter.map('App.User', {
name: {embedded: 'always'}
});
App.User = DS.Model.extend({
email: DS.attr('string'),
name: DS.belongsTo('App.UserName')
});
App.UserName = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string')
});

Categories