set controller attribute in promise before continue - ember.js

Hi I have a doubt in how using promises in Ember. Basically I want to setup the attributes of my controller before running what is next the promise, my code:
export default Ember.Controller.extend({
min: null,
max: null,
isValid: Ember.computed(function(){
var self = this;
var result = new Ember.RSVP.Promise(function(resolve, reject){
var url = "..."
Ember.$.getJSON(url).then(function(data){
if (data[0] === 0){
self.set('errorMessage', "It is a free book");
return false;
} else if (data[0] > 2000){
self.set('errorMessage', "You are poor, go for next");
return false;
} else {
console.log(data); # line 2 of console result
self.set('min', data[1]);
self.set('max', data[2]);
return true;
}
});
});
}
return result;
}),
actions: {
save: function(){
if (this.get('isValid')){
console.log('save action is fired. -- VALID' + '--' + this.get('maxPrice')); # line 1 of console result
} else {
console.log('save action is fired. -- INVALID');
}
}
}
});
The thing is in the third if statement, the code in save action is running before setting the attributes min and max inside the promise. Result in console:
> save action is fired. -- VALID--null
> [9, 1, 20]
Any idea how to set the values before the action go ahead?
Thanks,

There isn't much point in wrapping the jquery promise with another promise. Just use the jquery promise, return it, and then since this is an async world, you need to then off of that promise.
export default Ember.Controller.extend({
min: null,
max: null,
checkValid: function(url) {
var self = this;
return Ember.$.getJSON(url).then(function(data) {
if (data[0] === 0) {
self.set('errorMessage', "It is a free book");
return false;
} else if (data[0] > 2000) {
self.set('errorMessage', "You are poor, go for next");
return false;
} else {
console.log(data);#
line 2 of console result
self.set('min', data[1]);
self.set('max', data[2]);
return true;
}
});
},
actions: {
save: function() {
var self = this;
var url = ...;
this.checkValid(url).then(function(result) {
if (result) {
console.log('save action is fired. -- VALID' + '--' + self.get('maxPrice'));
} else {
console.log('save action is fired. -- INVALID');
}
});
}
}
});
Additionally when you're using the RSVP promise, you need to actually call resolve/reject for the promise to ever resolve or reject. Here's a quick video on how to use RSVP promises: https://www.youtube.com/watch?v=8WXgm4_V85E

Related

Emberjs - how to reset a field on a component after saving?

I have an embedded object called Comment, inside a Game. Each game can have many Comments.
When a user (called a Parent) views the game page, they can leave a comment.
The problem I have is that I cannot seem to reset the body of the comment field back to empty after the comment is saved.
This is the component:
MyApp.AddCommentComponent = Ember.Component.extend({
body: '',
actions: {
addComment: function() {
var comment, failure, success;
if (!!this.get('body').trim()) {
comment = this.store.createRecord('comment', {
body: this.get('body'),
game: this.get('game'),
parent_id: this.get('parent_id'),
parent_name: this.get('parent_name')
});
success = (function() {
this.set('body', '');
});
failure = (function() {
return console.log("Failed to save comment");
});
return comment.save().then(success, failure);
}
}
}
});
The error is on the 'this.set' line - this.set is not a function
All the examples I find are about doing this in a controller or by creating a new record upon route change (but the route is not changing in my example, since it is just adding another embedded object to the existing page).
You are using
this.set('body', '');
in success, but the scope of this here is changed, you need to keep the controller scope and set the body to empty string like
MyApp.AddCommentComponent = Ember.Component.extend({
body: '',
actions: {
addComment: function() {
var that = this;
var comment, failure, success;
if (!!this.get('body').trim()) {
comment = this.store.createRecord('comment', {
body: this.get('body'),
game: this.get('game'),
parent_id: this.get('parent_id'),
parent_name: this.get('parent_name')
});
success = (function() {
that.set('body', '');
});
failure = (function() {
return console.log("Failed to save comment");
});
return comment.save().then(success, failure);
}
}
}
});
When you introduce a function, you must remember that the value for this is not (necessarily) the same as the enclosing scope's value for this. Save the reference to the Component to use in a closure, like this:
MyApp.AddCommentComponent = Ember.Component.extend({
body: '',
actions: {
addComment: function() {
var comment, failure, success;
var self= this;
if (!!this.get('body').trim()) {
comment = this.store.createRecord('comment', {
body: this.get('body'),
game: this.get('game'),
parent_id: this.get('parent_id'),
parent_name: this.get('parent_name')
});
success = (function() {
self.set('body', '');
});
failure = (function() {
return console.log("Failed to save comment");
});
return comment.save().then(success, failure);
}
}
}
});

Ember - How to call common validation methods which returns a value

I have a validation method which checks for common validation of values in a input field like empty check, special characters check.
When I call a method using send('methodName'), this will not return a value.
I need to return a value and based on the value I can show messages based on the result.
Code:
Index Template:
{{input value=inputval placeholder='Enter Your Name'}}
<div class="submitdiv" {{action 'submitValue'}}>Submit Name</div>
App.js:
App.IndexController = Ember.ArrayController.extend({
inputval: ''
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['Jeevi', 'James', 'Tony'];
},
actions: {
submitValue: function(){
var self = this;
var temp_val = self.controller.get('inputval');
var is_valid = self.send('validateName', temp_val); //Need a value returned from this method call
if( is_valid ){
self.get('controller').model.addObject(temp_val);
} else {
alert('Enter a Name');
}
},
validateName: function(val){ // Need to return a value based on the validation result
if( val === "" ){
return false;
} else {
return true;
}
}
}
});
JSBin Demo Link
You can use a callback,
js
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['Jeevi', 'James', 'Tony'];
},
actions: {
submitValue: function(){
var self = this;
var temp_val = self.controller.get('inputval');
self.send('validateName', temp_val, function(is_valid){
if( is_valid ){ self.get('controller').model.addObject(temp_val);
} else {
alert('Enter a Name');
}
});
},
validateName: function(val,callback){
if( val === "" ){
callback(false);
} else {
callback(true);
}
}
}
});
http://jsbin.com/ziwosepini/1/edit?html,js
with this approach it is also possible to support ajax/promises, in case a validation needs to be carried out on the server.
http://jsbin.com/cehabojahe/1/edit?html,js

how to refresh after server request for login with ember?

I have the following code as ember login controller. It works by checking if user is logged_in, but it always returns false.
The is_logged_in needs first a refresh before server returns true and then it works. How do I make this work correctly? Also the transition to route isn't working.
App.IndexController = Ember.ObjectController.extend({
actions: {
userLogin: function(user) {
$.post("http://siteurl/api/authentication/login/?username=" + user.username + "&password=" + user.password + "");
$.getJSON("http://siteurl/api/authentication/is_logged_in/", function(json) {
alert(json.logged_in);
if(json.logged_in == true){
transitionTo('nieuws');
}
if(json.logged_in == false){
alert("login incorrect");
}
});
}
}
});
The second request should be called after the first one has completed. Also you have a couple of errors in your code. Try this:
App.IndexController = Ember.ObjectController.extend({
actions: {
userLogin: function(user) {
var self = this;
$.post("http://siteurl/api/authentication/login/?username=" + user.username + "&password=" + user.password + "", function() {
$.getJSON("http://siteurl/api/authentication/is_logged_in/", function(json) {
alert(json.logged_in);
if(json.logged_in == true){
self.transitionToRoute('nieuws');
}
if(json.logged_in == false){
alert("login incorrect");
}
});
});
}
}
});
In addition, as #Matthew Blancarte points out in a comment, you shouldn't need two requests to login a user. Ther first POST request should return a success/fail result.

Is there a more efficient way to filter through a collection with computed properties?

In short, I am creating a table that is sortable and is filterable by whether the item is new, updated or needs to be deleted. The FilteredParts property needs to observe both the query, sortBy and model.#each.isDirty in order to ensure the table is up to date. Changing filters and sorting are quick however if I want to update any model in the collection it very slow. Is there a way to use model.#each.isDirty or something similar so that it is not so taxing?
Here is my controller:
App.VendorPartsController = Ember.ArrayController.extend(App.PartTableMixin,{
queryParams: ['query','sortBy'],
query: "all",
hasChanges: function(){
if(this.get('filteredParts').isAny('isDirty',true))
{
return true;
}
return false;
}.property('filteredParts.#each.isDirty'),
hasNew: function() {
if(this.get('filteredParts').isAny('isNew',true))
{
return true;
}else{
return false;
}
}.property('filteredParts.#each.isNew'),
hasUpdated: function() {
var parts = this.get('filteredParts');
return parts.any(function(part){
return part.get('isDirty') && !(part.get('isNew')) && !(part.get('deletable'));
});
}.property('filteredParts.#each.isDirty'),
hasDeleted: function() {
if(this.get('filteredParts').isAny('deletable',true))
{
return true;
}
else
{
return false;
}
}.property('filteredParts.#each.deletable'),
filteredParts: function(){
var parts = this.get('model');
var query = this.get('query');
var sortBy = this.get('sortBy');
switch(query){
case "new":
return parts.filterProperty('isNew',true).sortBy(sortBy);
break;
case "updated":
return parts.filter(function(part){
return part.get('isDirty') && !(part.get('isNew')) && !(part.get('deletable'));
}).sortBy(sortBy);
break;
case "deleted":
return parts.filterProperty('deletable',true).sortBy(sortBy);
break;
case "all":
return parts.sortBy(sortBy);
break;
}
}.property('query','sortBy','model.#each.isDirty'),
actions: {
undoAll: function() {
this.get('model').forEach(function(part){
part.rollback();
})
this.transitionToRoute('vendor.parts');
}
}
})
Here is a mixin that I will probably add back into the controller:
App.PartTableMixin = Ember.Mixin.create({
sortAscending: false,
sortBy: 'vendor_part_number',
outOfParts: function()
{
if(this.get('filteredParts').length < 1)
{
return true;
}else
{
return false;
}
}.property('filteredParts.length'),
actions: {
trash: function(model){
if(model.get('isNew'))
{
model.rollback();
}
else
{
model.set('deletable',true);
}
},
undo: function(model) {
model.rollback();
}
}
});

The best way to achieve a find in ember js and not lose the current controller scope

I want to do an ember js find based on an id.
If an object with that id exists I would like to perform some logic on that object.
So, I do so based on the following code:
Cluey.UsersController = Ember.ArrayController.extend({
keypadNum: "",
loginWithPin: function() {
var res;
console.log("Login with pin: " + this.get('loginPin'));
res = Cluey.User.find({
pin: this.get('loginPin')
});
return res.on('didLoad', function() {
var user;
if (res.get('firstObject') != null) {
user = res.objectAt(0);
return this.doLogin(user);
} else {
return alert("User not found with pin " + this.get('loginPin'));
}
});
},
doLogin: function(user) {
//some code
}
});
The problem is that once I am in the res.on('didLoad') callback, I lose the scope of the controller, and therefore when I try to access this.get("loginPin"), it is returned as undefined.
Does anyone know how to solve this.
thanks!
If you pass an object as the second parameter in the on event, it will be your context in the callback.
You can pass this as the second parameter for the didLoad event:
res.on('didLoad', this, function() {
var user;
if (res.get('firstObject') != null) {
user = res.objectAt(0);
return this.doLogin(user);
} else {
return alert("User not found with pin " + this.get('loginPin'));
}
});
You could create a var called self and assign this to it.
Cluey.UsersController = Ember.ArrayController.extend({
keypadNum: "",
var self = this;
loginWithPin: function() {
var res;
console.log("Login with pin: " + this.get('loginPin'));
res = Cluey.User.find({
pin: self.get('loginPin')
});
return res.on('didLoad', function() {
var user;
if (res.get('firstObject') != null) {
user = res.objectAt(0);
return this.doLogin(user);
} else {
return alert("User not found with pin " + this.get('loginPin'));
}
});
},
doLogin: function(user) {
//some code
}
});