New at EmberJS and need some help/advice on my login code - javascript

I'm working on an EmberJS frontend to my Spring backend API and the first thing I needed to tackle was the "login" screen. I've been reading tutorials across the web and whatever I can find on Ember, however, the problem seems that there are just too many different versions of the same tutorials and different ways of doing the same thing. It's been confusing me, but, after a lot of toiling away, I think I may have finally managed to get my login screen to work (partly).
It authenticates nicely using ajax and I can see in the dev console that everything is working well.
Before I proceed any further, I first wanted to have people's opinions about the ember code I have written thus far and if it is within "best practices" for an ember application. Also, if there are any better ways to go about solving the same problem.
Secondly, I have no idea how to switch to a different view on a successful login. I admit I'm still not familiar with the concepts of ember, but the tutorials online just keep confusing me.
I'd really appreciate any help here. I'm a fast learner and I think that I can take things from here depending on the answers.
Here's the code from my app.js file:
App = Ember.Application.create();
//------------------------------------------------------------
// Hold the details of the logged-in user
//------------------------------------------------------------
App.LoggedInDetails = Ember.Object.create({
Fullname: null,
CompanyName: null,
TokenID: null,
setDetails: function(fullname, companyname, tokenid)
{
this.Fullname = fullname;
this.CompanyName = companyname;
this.TokenID = tokenid;
},
clearDetails: function()
{
this.Fullname = null;
this.CompanyName = null;
this.TokenID = null;
}
});
//------------------------------------------------------------
App.ApplicationView = Ember.View.extend({
templateName: 'logged-out'
});
App.ApplicationController = Ember.Controller.extend({
isError: false,
errorMessage: null,
authenticate: function()
{
var email = this.get('email');
var password = this.get('password');
var url = 'https://api.example.com/security/authenticateUser.json';
$.ajax({
url: url,
type: 'POST',
dataType:'json',
data: {email: email, passwd: password},
crossDomain: true,
context: this,
success: this.authenticateCompleted
});
console.log('Url: ' + url);
},
authenticateCompleted: function(data)
{
// Login was a success!
if(data.status === 'OK')
{
console.log('status: ' + data.status);
console.log('fullName: ' + data.fullName);
console.log('tokenId: ' + data.tokenId);
console.log('companyName: ' + data.companyName);
// Populate the LoggedInDetails object
App.LoggedInDetails.setDetails(data.fullName, data.companyName, data.tokenId);
this.set('isError', false);
}
else
{
App.LoggedInDetails.clearDetails();
this.set('errorMessage', 'Invalid Email/Password Combination');
this.set('isError', true);
console.log(data.status);
console.log(data.description);
}
}
});
//------------------------------------------------------------
App.Router = Ember.Router.extend({
enableLogging: true,
root: Ember.Route.extend({
index: Ember.Route.extend({
route: '/',
connectOutlets: function(router) {
router.get('applicationController').connectOutlet({
viewClass: App.ApplicationView,
controller: router.get('applicationController')
});
}
})
})
});
//------------------------------------------------------------
App.LoggedInView = Ember.View.extend({
templateName: 'logged-in'
});
App.LoggedInController = Ember.Controller.extend({
Fullname: App.LoggedInDetails.get("Fullname")
});
//------------------------------------------------------------
App.initialize();
My problem stems from switching from the "logged-out" default view to the "logged-in" view, which is the actual UI of my application.
Many thanks for any help.

Simplest approach: add an isLoggedIn property to ApplicationController and set it to true when the user authenticates. Make ApplicationView render a template that uses {{#if isLoggedIn}} ... {{else}} ... {{/if}} to switch between the logged in view and the non-logged in view.

Related

Ember 2.0 router does not load model data?

I have in my router.js:
Router.map(function() {
this.route('portfolio', function() {
this.route('company', { path:'/company/:id' });
});
}
And in my routes/portfolio/company.js:
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
var companyId = params.id;
return new Ember.RSVP.hash({
company: Ember.$.ajax({ url: '/api/company/'+companyId, dataType: "json", type: 'GET' })
}).then(function(message) {
return message;
}, function(error) {
console.log( error );
});
}
});
My route and template is loading fine, when I navigate to app/portfolio/company/1, but for some reason when I navigate to that route, Ember wont load the model (no error, but the {{model}} variable does not get populated in template). Only when I refresh the page, Ember loads the model?! I am a bit confused now...
Edit: added missing param and added better description
I think in your template or in controller you are using model like so
model.company replace it with model, and remove extraneous RSVP.hash
because Ember.$.ajax already returns promise which model hooks can handle
so in ES6 (ember-cli supports it) your model hook should look like this
model({ id }) {
return Ember.$.ajax('/api/company/' + id);
}
with above things everything should work, what was happening I think you were passing just model to {{link-to}} while your controller or template expecting model.company so was breaking things

Models are not serialized with Ember.js and WebApiAdapter

I'm trying to use the Ember.js MVC4 Spa Template with my own Models, but I'm not getting this to work.
For now, the serverside code is is working. The result to the browser is correct. But Ember-Data, or the custom WebApi - Serializer, is not able to prepare the Data.
I have two Models:
Patient:
App.Patient = DS.Model.extend();
App.Patient.reopen({
patientId: DS.attr('number'),
firstName: DS.attr('string'),
lastName: DS.attr('string'),
aufenthalte: DS.hasMany('aufenthalt'), //, { async: true }
fullName: function () {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName'),
});
App.PatientSerializer = DS.WebAPISerializer.extend({
primaryKey: 'patientId',
// ember-data-1.0.0-beta2 does not handle embedded data like they once did in 0.13, so we've to update individually if present
// once embedded is implemented in future release, we'll move this back to WebAPISerializer.
// see https://github.com/emberjs/data/blob/master/TRANSITION.md for details
extractArray: function (store, primaryType, payload) {
var primaryTypeName = primaryType.typeKey;
var typeName = primaryTypeName,
type = store.modelFor(typeName);
var data = {};
data[typeName] = payload;
data.aufenthalte = [];
var normalizedArray = payload.map(function (hash) {
hash.aufenthalte.map(function (aufenthalt) {
data.aufenthalte.push(aufenthalt);
});
hash.aufenthalte = hash.aufenthalte.mapProperty('aufenthaltId');
return hash;
}, this);
payload = data;
return this._super.apply(this, arguments);
},
normalizeHash: {
patient: function (hash) {
hash.patientId = hash.id;
return hash;
}
}
});
Aufenthalt:
App.Aufenthalt = DS.Model.extend({
aufenthaltId: DS.attr('number'),
name: DS.attr('string'),
patientId: DS.attr('number'),
patient: DS.belongsTo('patient'),
});
App.AufenthaltSerializer = DS.WebAPISerializer.extend({
primaryKey: 'aufenthaltId',
normalizeHash: {
aufenthalte: function (hash) {
hash.aufenthaltId = hash.id;
return hash;
},
}
});
When I get a List of "Patients" from my Controller, the Datamodels are filled correctly (I can check it in the Chrome Ember plugin.) When I hit a Action with the Patient Id, I get the error: "Error while loading route: TypeError: Cannot set property 'store' of undefined"
Thank You!
Did you added the proper router in app/routes folder, controller in app/controllers folder, and corresponding views and templates? Feel free to psot a link to your sample solution so I can download and have a look.
=== Update 2/22/2014 ===
I fixed the code. You should be able to download the modified solution from https://www.dropbox.com/s/4j3vbczqr4nx68m/EmberVSTemplateModified.zip. You should do a windiff on the two directories to see the changes. I need to change a few places to make it work for your scenario, including:
patient.js, make it directly extend from RESTSerialzer, and add extractSingle implementation.
change template of patsucheautocomplete.hbs
added patient\index.hbs . You should be able to remove patient.hbs file
paitentview.js (may not be necessary as it's all default)
modified controllers\htmlhelperextensions.cs, to make it work correctly for sub folder templates in debug mode.

Backbone model - extending api calls

I'm working on my first nodejs/backbone project. What I need to do is to extend user model api with additional methods. As REST uses universal post/get/put request, how do you extended backbone model with other api calls (ie. block user account where I don't want to update user and make /user/deactivate url)?
I can take ugly routes, but I looking for the "right way" from pros.
My backbone model
define(["jquery", "backbone"],
function($, Backbone) {
var User = Backbone.Model.extend({
urlRoot: '/user',
defaults: {
username: '',
password: '',
email: ''
}
});
return User;
}
);
My nodejs "router"
app.put('/user', userController.register);
app.post('/user', userController.update);
app.get('/user', userController.list);
app.delete('/user', userController.delete);
Why not add block and deactivate attributes to your model, then just use standard REST / CRUD API calls.
Then your actions block and deactivate would just be standard model updates, with logic to handle blocked and active model states in your API methods.
define(["jquery", "backbone"],
function($, Backbone) {
var User = Backbone.Model.extend({
urlRoot: '/user',
defaults: {
username: '',
password: '',
email: '',
blocked: false,
active: true
},
block: function () {
this.set('blocked', true);
this.save();
},
deactivate: function () {
this.set('active', false);
this.save();
},
});
return User;
}
);
EDIT - Based on your comment, the need to distinguish between updates
If you need to distinguish between field updates on the server, in order to run route specific validation for example. Then you're probably going to need to call custom routes for each specific action. A neat way of doing this would be to override the url during the call to save the model.
An updated model example.
define(["jquery", "backbone"],
function($, Backbone) {
var User = Backbone.Model.extend({
urlRoot: '/user',
defaults: {
username: '',
password: '',
email: '',
blocked: false,
active: true
},
block: function () {
this.set('blocked', true);
this.save(this, { url: '/user/block' });
},
deactivate: function () {
this.set('active', false);
this.save(this, { url: '/user/deactivate' });
},
});
return User;
}
);
Then you would have the following routes
app.put('/user', userController.register);
app.post('/user', userController.update);
app.get('/user', userController.list);
app.delete('/user', userController.delete);
app.post('/user/block', userController.block);
app.post('/user/deactivate', userController.deactivate);

What is the best way to add server variables (PHP) in to the Backbone.model using require.js?

I'm not sure what is the elegant way to pass server variables in to my Model.
For example, i have an id of user that has to be implemented on my Model. But seems like Backbone with require are not able to do that.
My two options are:
Get a json file with Ajax.
Add the variable on my index.php as a global.
Someone know if exists a other way. Native on the clases?
Trying to make work the example of backbonetutorials. I am not able to throw a callback when the method fetch().
$(document).ready(function() {
var Timer = Backbone.Model.extend({
urlRoot : 'timeserver/',
defaults: {
name: '',
email: ''
}
});
var timer = new Timer({id:1});
timer.fetch({
success: function(data) {
alert('success')
},
fail: function(model, response) {
alert('fail');
},
sync: function(data) {
alert('sync')
}
});
});
The ajax request it has been threw. But does not work at all. Because any alert its dispatched.
var UserModel = Backbone.Model.extend({
urlRoot: '/user',
defaults: {
name: '',
email: ''
}
});
// Here we have set the `id` of the model
var user = new Usermodel({id: 1});
// The fetch below will perform GET /user/1
// The server should return the id, name and email from the database
user.fetch({
success: function (user) {
console.log(user);
}
})
The server will reply with a json object then you can leave the rendering part for your backbone. Based on a template for the user.
You may also want to check these out: http://backbonetutorials.com/

AngularJS Services (Update/Save)

New to AngularJS and trying to get a grasp of the framework, and trying to build a basic CRUD app. I can't seem to figure out what is needed to Update an existing record. Here is my service:
angular.module('appServices', ['ngResource']).
factory('App', function ($resource) {
var Item = $resource('App/:AppId', {
//Default parameters
AppId: '#id'
}, {
//Actions
query: {
method: 'GET',
isArray: true
},
getById: {
method: 'PUT'
},
update: {
method: 'POST'
}
});
return Item;
});
I can run a basic Get all query, and getById to populate an edit form, but that's where I'm stuck. Here is example code for getById
$scope.apps = App.query();
$scope.getEdit = function(AppId) {
App.getById({id:AppId}, function(app) {
$scope.original = app;
$scope.app = new App(app);
});
};
$scope.save = function() {
//What type of information should go here?
//Do I need to make changes to the appServices?
};
I guess, I'm just not sure what's next concerning Updating existing information, or how the "app" object gets passed to the API, can anyone point me in the right direction, or show me a quick update method?
This is a really messy way of handling save operations in angular. For one - you should not be using PUT operations for retrieval requests and secondly - all of this is already built-in to angular. See below.
var Item = $resource( 'App/Details/:AppId', { AppId: '#id' } );
var item = Item.get({ id: 1 }, function( data ) {
data.setAnothervalue = 'fake value';
data.$save();
);
What I'm doing here is retrieving an "Item" and then immediately saving it with new data once it's returned.
Angular JS provides a stack of defaults already, including query, save, remove/delete, get.etc. And for most RESTful APIs, you really shouldn't need to add much, if anything at all. See the resource docs for more information, particularly the information on defaults: http://docs.angularjs.org/api/ngResource.$resource
Additionally, once you get a handle on that - you may want to use $save for both create/update operations, but using POST/PUT (RESTful conventions). If you do, see my article that I wrote about not too long ago: http://kirkbushell.me/angular-js-using-ng-resource-in-a-more-restful-manner/
After doing a bit more research, and reviewing Daniel's link (thanks). I got it working.
Controller method:
$scope.save = function() {
$scope.app.update();
};
Service Factory:
var Item = $resource('App/Details/:AppId', {
//Default parameters
AppId: '#id'
}, {
//Actions
query: {
method: 'GET',
isArray: true
},
getById: {
method: 'PUT'
},
update: {
method: 'POST'
}
});
Item.prototype.update = function (cb) {
console.log(this.AppId);
return Item.update({ AppId: this.AppId },
angular.extend({}, this, { AppId: undefined }), cb);
};
return Item;

Categories

Resources