Ember - clear form after submitting - forms

I created very simple Ember app, using Ember Data. There is one form where the user creates the entity and submits. It's in BandsNewView (created automatically by Ember), controlled by BandsNewController:
App.BandsNewController = Ember.Controller.extend({
cancel: function() {
this.transitionTo('bands');
},
save: function() {
App.Band.createRecord(this);
this.get('store').commit();
this.set('name');
this.set('description');
this.transitionTo('bands');
}
});
I wonder whether there is simplier solution to "clean up" (i.e empty) the form after saving new Band entity? Can I say something like this.set(), which would empty all the fields? Or is my approach essentially wrong and should I do it completely differently?

The pattern that I've been enjoying is creating and destroying the object on enter and exit of the route itself.
App.BandsNewRoute = Ember.Route.extend({
model: function(params) {
return App.Band.createRecord({});
},
save: function() {
this.get('currentModel.store').commit();
return this.transitionTo('bands');
},
exit: function() {
var model = this.get('currentModel');
if (model.get("isNew") && !model.get("isSaving")) {
return model.get('transaction').rollback();
}
}
});
As you can see, it makes the exit function a little more complex, but it will be exactly the same for every object creation route, so you can factor it out. Now your templates can just bind straight to the model's properties and the model will be saved on save, or rolled back on exit (which will clear the form)
If you are planning on possibly changing other data models and not saving them, or have unsaved models, a way to safely clear the model away is to put it in it's own transaction. I only tend to use this though for objects that are not the main focus of my current flow.
App.BandsNewRoute = Ember.Route.extend({
model: function(params) {
var transaction = this.get('store').transaction();
return transaction.createRecord(App.Band, {})
}
});
Everything else can stay the same.

Related

MongoDB: can't return random document from collection

I'm working on a word game and am trying to return a random wordpair (my collection) on a page load. I'm using Express and have adapted my code from this tutorial if that's of any use.
A GET request renders my page just fine, and I'm trying to send a random WordPair object alongside the title:
router.get('/', function(req, res, next) {
res.render('play', { title: 'play', random_wordpair: wordpair_controller.wordpair_random});
});
The wordpair_random function is here inside a controller file I've made (which also successfully manages listing the wordpairs and creating new ones etc).
// Get random WordPair
exports.wordpair_random = function() {
WordPair.aggregate(
[{
$sample: {
size: 1
}
}]
)
.exec(function(err, random_wordpair) {
if (err) {
return next(err);
}
console.log(random_wordpair);
return random_wordpair;
});
};
Then inside a play.pug template, I'm simply trying to display this result:
h3 random wordpair selection is: #{random_wordpair}
But all I can see is the function rendered as HTML text. Can anyone tell me what I'm doing wrong?
I also understand looking at the documentation for MongoDB $sample aggregation that I need to be calling my function on the database object, but I've seen various examples and some don't do this. When I try calling db.wordpair.aggregate(...) (or WordPair or wordpairs as it appears in mLab) directly after initializing db in my app.js file, I get undefined errors. My db object doesn't seem to contain the correct data for this request.
Thanks!
I guess you're writing this in Node.JS. A core feature in Node.JS is non-blocking IO model. That means, the code won't wait for a database call to complete to move on.
Another concept you need to get it right is that Node.JS, being a variation of JavaScript, in nature is a functional programming. Assigning a function to a property of a JSON object like below won't cause the function to execute. It simply creates a pointer to the function body, that's why your application prints the function itself.
{ title: 'play', random_wordpair: wordpair_controller.wordpair_random}
To fix this, use a callback
exports.wordpair_random = function(callback) {
WordPair.aggregate([$sample: {size: 1}}]).exec(callback);
};
Then in you web function:
router.get('/', function(req, res, next) {
wordpair_controller.wordpair_random(function(err, result) {
//Handle errors if needed.
res.render('play', { title: 'play', random_wordpair:result });
})
});

How to fetch a Backbone Collection from sequelize-restful-extended in one call

I have a model called Instance which works fine.
define([], function(){
return Backbone.Model.extend({
urlRoot:'/api/Instances',
parse:function(content){
return content.data;
}
});
});
My REST at here
http://localhost:3000/api/Instances/1
returns this
{"status":"success","data":{"id":1,"name":"bangladesh","write":null,"read":null,"createdAt":"2015-09-01T23:03:16.000Z","updatedAt":"2015-09-01T23:03:16.000Z","UserId":1}}
hence the parse function in my model. All good so far.
If I just call
http://localhost:3000/api/Instances
Then I get a block of all my records,
{"status":"success","count":212,"data":[
{"id":1,"name":"bangladesh","write":null,"read":null,"createdAt":"2015-09-01T23:03:16.000Z","updatedAt":"2015-09-01T23:03:16.000Z","UserId":1},
{"id":2,"name":"abqride","write":null,"read":null,"createdAt":"2015-09-01T23:03:58.000Z","updatedAt":"2015-09-01T23:03:58.000Z","UserId":1},
....
And my collection code is just this
define(['models/instance.js'], function(Model){
return Backbone.Collection.extend({
url:'/api/Instances',
model:Model,
parse:function(content){
return content.data;
}
})
});
The above code for the Collection will create 212 models. I've checked that with an initialise function in the model just to see if it was being called OK with the right data, and it is.
But in my view code when I go
this.collection.each(function(model) {
console.log("model id="+model.get("id")+" count="+count++);
out+=model.get("id")+"="+model.get("name")+"<br>";
});
there's nothing in these models, but there are 212 of them, I just get "undefined=null" 212 times.
I can see three options, two of which involve customizing the use of Backbone: 1. Calling collection.sync manually and then executing custom code afterward, 2. Passing a custom option in the initial collection.fetch() and looking for it in the Model parse() method.
These two options don't solve the problem at the source, however, since the concern is at the initial response level. In order to apply a response-level filter to your data, try overriding Backbone.ajax() before starting your application:
Backbone.ajax = function () {
var settings = arguments[1] || arguments[0]; // jQuery.ajax(url[, settings])
var success = settings.success;
settings.success = function (data, status, xhr) {
if (success) { success(data.data, status, xhr); }
};
return Backbone.$.ajax.apply(Backbone.$, arguments);
};

Meteor - no more callbacks for "findOne" function

i'm working on a Meteor project, and I must say that isn't easy at all, especially for one thing: callbacks !
Everything is async, so I wonder how do I must do to get results from my mongodb.
var user = Meteor.users.findOne({username: "john"});
return (user); // sometimes returns "undefined"
...
var user = Meteor.users.findOne({username: "john"});
if (user) // so ok, I check if it exists!
return (user); // Cool, I got my user!
return (); // Ok and what should I return here? I want my user!
I don't want to be dirty and put like setTimeout everywhere.
Anybody has a solution for this ?
EDIT :
I noticed in router.js with console.log that my data is returned 4 times. 2 times with an undefined value and 2 other times with the expected value. In the view, it's still undefined.
Why the router passes like 4 times in this route ? Does it display the first result of the return value in the router ?
What should I return if the find() doesn't find anything ?
EDIT 2: Here is some code to understand.
this.route('profilePage', {
path: 'profil/:_id?',
waitOn: function() {
return [
Meteor.subscribe('article', { prop: this.params._id}), // id can be id or username
Meteor.subscribe('article', { userId: this.params._id}), // id can be id or username
Meteor.subscribe('params'),
Meteor.subscribe('profil', (this.params._id ? this.params._id : Meteor.userId()))
];
},
data: function() {
if (this.params._id) {
var user = Meteor.users.findOne(this.params._id);
if (!user)
user = Meteor.users.findOne({username: this.params._id});
console.log(user);
return user;
}
else if (Meteor.userId())
return Meteor.user();
else
Router.go("userCreate");
}
});
I get this on the console:
http://puu.sh/debdJ/69419911f7.png
(text version following)
undefined
undefined
Object_id: "o3mgLcechYTtHPELh"addresses: (....)
Object_id: "o3mgLcechYTtHPELh"addresses: (....)
findOne(yourId) is a sync method which is equivalent to find({ _id: yourId}, callback). The difference is that find() allows you to define a callback. If you don't pass a callback to find() this method will be sync.
check wrapAsync: http://docs.meteor.com/#/full/meteor_wrapasync
It allows you to code in a sync style with a async operations.
Free lesson on EventedMind: https://www.eventedmind.com/feed/meteor-meteor-wrapasync
My experience thus far is that the Meteor Mongodb package is that the functions do not generally provide callbacks (for some reason insert does...), the functions are atomic (thus sync).
There are meteor packages that can make Mongodb async if you want (I havn't tried any).
I guess this sync approach is in line with the simple maintenance goal of Mongodb. Thinking about it, one of my pet peeves using Node is working with async callback waterfalls/nests, they are a pain to create and maintain... and hopefully this will make my code easier to read and understand and change...
var future = new Future();
var _h = Hunts.findOne({huntId});
if(_h) {
future.return(_h)
} else {
return future.wait();
}
on server/startup.js you need:
Future = Npm.require('fibers/future');

Angular service not updating on model change

In may app I have a service which holds my tasks:
app.factory('Tasks', function () {
var tasks = [];
return {
getAll: function () { return tasks; },
addOne: function (task) { tasks.push(task); },
openBy: function(owner) {
return _.where(tasks, {owner: owner, status: 'open'});
},
doneBy: function(owner) {
return _.where(tasks, {owner: owner, status: 'closed'});
},
};
});
I then show, per owner, either their open tasks or closed tasks.
The problem is that when I update the tasks by using Tasks.addOne(task); the views that use Tasks.openBy(owner) don't get updated. The ones that use Tasks.getAll() do.
Is this because I am returning a new array? If so is there a way of telling the controller to update what it has? Or am I just doing this entirely wrong in the first place and is there a better way to do it?
Any help would be greatly appreciated.
Matthew
What you could do is to call the openBy function in the controller (or directive) rather than in the view and wrap it into a $scope.$watch invocation. As an example:
// Controller body
app.controller('TasksCtrl', function($scope, Tasks) {
$scope.allTasks = Tasks.getAll();
$scope.$watch('allTasks', function() {
// Assume owner is the user and it's initialised somewhere above
$scope.ownedTasks = tasks.openBy(owner);
}, true);
});
This should work, even though I think that it should be possible to do something more elegant maybe!

Incrementally update Kendo UI autocomplete

I have a Kendo UI autocomplete bound to a remote transport that I need to tweak how it works and am coming up blank.
Currently, I perform a bunch of searches on the server and integrate the results into a JSON response and then return this to the datasource for the autocomplete. The problem is that this can take a long time and our application is time sensitive.
We have identified which searches are most important and found that 1 search accounts for 95% of the chosen results. However, I still need to provide the data from the other searches. I was thinking of kicking off separate requests for data on the server and adding them the autocomplete as they return. Our main search returns extremely fast and would be the first items added to the list. Then as the other searches return, I would like them to add dynamically to the list.
Our application uses knockout.js and I thought about making the datasource part of our view model, but from looking around, Kendo doesn't update based on changes to your observables.
I am currently stumped and any advice would be welcomed.
Edit:
I have been experimenting and have had some success simulating what I want with the following datasource:
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: window.performLookupUrl,
data: function () {
return {
param1: $("#Input").val()
};
}
},
parameterMap: function (options) {
return {
param1: options.param1
};
}
},
serverFiltering: true,
serverPaging: true,
requestEnd: function (e) {
if (e.type == "read") {
window.setTimeout(function() {
dataSource.add({ Name: "testin1234", Id: "X1234" })
}, 2000);
}
}
});
If the first search returns results, then after 2 seconds, a new item pops into the list. However, if the first search fails, then nothing happens. Is it proper to use (abuse??) the requestEnd like this? My eventual goal is to kick off the rest of the searches from this function.
I contacted Telerik and they gave me the following jsbin that I was able to modify to suit my needs.
http://jsbin.com/ezucuk/5/edit