class methods in Backbone - javascript

I'm trying to implement authentication with Devise (an authentication gem for Rails) using Backbone. Users can sign out of Backbone by sending the DELETE request to /users/sign_out/ so I couldn't get this link to work because if I click it it's a GET request
<li>sign out</li>
I then created a logout method on the User model, but to trigger it I have to have an instance of the user model (obviously). I created a logout method in the router that gets triggered by navigating to the logout route, but since I can only call logout on the user model with an instance of it, I'm creating a new model in the logout method just to call logout.
"logout": "logout"
},
logout: function(){
var foo = new app.Models.User
foo.logout();
}
This is obviously a bad idea but I don't know what else to do. Can you recommend what I should be doing instead? Is there a way to make the logout a class method so I don't have to instantiate a new model just to logout or something else?
Update
This is the createUser method in the User model that sends the registration data to devise. In the success callback, it assigns the session to a variable window.app.current_user = userSession;. I also have a logout method on the user model that I try to call from the router like this
logout in router
logout: function(){
window.app.current_user.logout();
}
--
app.Models.User = Backbone.Model.extend({
initialize:function () {
},
createUser: function() {
var user = {};
user['email'] = this.get("email");
user['password'] = this.get("password");
user['password_confirmation'] = this.get("password_confirmation");
var registration = {};
registration['user'] = user;
var _this = this;
$.ajax({
url: '/users.json',
type: "POST",
data: {user: user, registration: registration},
success: function(userSession, response) {
window.app.current_user = userSession;
},
... code ommitted
logout: function(){
var me;
console.log("Logging out...");
me = this;
return $.ajax({
url: '/users/sign_out',
type: "DELETE",
dataType: "json",
success: function(data, textStatus, jqXHR) {
window.app.current_user = '';
},
error: function(jqXHR, textStatus, errorThrown) {
return alert("Error logging out: " + errorThrown);
}
});
},

I am slightly confused why you would want to trigger a logout function when the User model has not already been created. Could you please explain your reasoning behind having this logout function in your router?
Personally, I would have a Session model which listens to the click event of your link. This will then call a logout method which will make the DELETE request.
UPDATE
Here is a quick JsFiddle which shows creating a model and attaching it to a global variable:
http://jsfiddle.net/Francium123/eBG3E/2/
var User = Backbone.Model.extend({
initialize:function () {
this.name = "MyName";
this.password = "password"
},
login:function(){
console.log("login called");
},
logout: function(){
console.log("logout called");
}
});
window.MyModels = window.MyModels || {};
window.MyModels.User = new User();
console.log(window.MyModels.User.login());
console.log(window.MyModels.User.logout());
Please note that this is just an example, I doubt you would want to store the password in the model!
Additionally you should be able to use Backbone Models fetch(GET), save(POST/PUT), destroy(DELETE) methods instead of writing ajax requests directly in the model. If needs be you can override the models sync method.

Related

Asynchronous Add/Update save method not updating

I am building a .NET page for a project that adds a new City and State for a new user or updates the City and state if their ID is already in the database. Everything is working fine except for the fact that if a past user clicks submit to update their information, an entirely new entry is added to the database.
I have created the method already in the repository listed below.
public async Task<LocationViewModel> SaveLocationAsync(LocationViewModel model)
{
try
{
var location = new Location()
{
City = model.City,
State = model.State
};
if (model.Id != 0)
{
location.Id = model.Id;
}
_dbcontext.Location.AddOrUpdate(location);
await _dbcontext.SaveChangesAsync();
return model;
}
catch (Exception ex)
{
model.Error = true;
model.ErrorMessages = new List<string>()
{
string.Format("Something went wrong - Message: {0} \n Stack Trace: {1}", ex.Message,
ex.StackTrace)
};
return model;
}
}
I have also built a controller that saves and updates existing records asynchronously shown below.
[System.Web.Mvc.AllowAnonymous]
[System.Web.Http.HttpPost]
public async Task<LocationViewModel> SaveLocationApiAsync(LocationViewModel model)
{
var result = new LocationViewModel();
if (ModelState.IsValid)
{
result = await _locationRepository.SaveLocationAsync(model);
}
return result;
}
In addition, I have added added all of my routes and references.
Why is a new entry put in the database instead of the current one updating? The Javascript is shown below.
self.Submit = function () {
if (self.errors().length !== 0) {
self.errors.showAllMessages();
return;
}
if (isNumber(locationId)) {
self.Location().LocationId(locationId);
swal("Success", "Thank you for your submission \nYour information has been updated.", "success");
}
var newData = ko.mapping.toJSON(self.Location());
var url = "/Admin/SaveLocationApiAsync/Post/";
$.ajax({
url: url,
method: "POST",
data: newData,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (result) {
if (result.Error === true) {
swal("Error", result.ErrorMessages.join('\n'), "error");
} else {
//TOdo
}
},
error: function () {
swal("Error", "Something went wrong.\nPlease contact help.", "error");
}
});
};
I apologize if it is a lot. I have checked everything repeatedly and have fixed all bugs. I am out of ideas.
Thanks in advance.
Your url looks to the controller action seems incorrect. You have var url = "/Admin/SaveLocationApiAsync/Post/"; when it should be var url = "/Admin/SaveLocationApiAsync";
Another approach to getting the correct url would be:
var url = '#Url.Action("SaveLocationApiAsync", "<ControllerName>")';
Also, in your ajax error handler you can get the HTTP status code and error message, which would help.
error: function (jqXHR, textStatus, errorThrown) {
swal("Error", "Something went wrong.\nPlease contact help.", "error");
}
EDIT:
I should have prefaced that using Url.Action works when your JavaScript is in a view (assuming Razor view in this case).
Fiddler is great tool to use when debugging ajax calls.

Callback basics using Backbone.js

I'm using backbone to post a login form to my server. After it queries the database it will flip a boolean value allowing me to retrieve GET responses from the server. The problem is that it tries to fetch (i think) before my login is validated. Given this code:
App.Login.add(newContact);
var out = newContact.save();
App.Contacts.fetch();
How do i write a callback to have it first finish newContact.save() before fetching Contacts?
This is what I have so far, but it never succeeds:
login: function(event) {
App.Browser.navigate('contacts');
event.preventDefault();
var $form = this.$('.login form');
var newContact = new App.Models.Login({
userName: $('input.userName', $form).val(),
passWord: $('input.passWord', $form).val(),
});
App.Login.add(newContact);
newContact.save({userName:"Frank"},{
wait: true,
success: function(model, response){
console.log('success');
},
error: function(){
console.log('error');
}
});
Model.save() accept callback to handle success or failure . which the code like:
App.Login.add(newContact);
var out=newContact.save(attributes,{
wait: true,// wait for the sever response finish
success:function(model, response,options){
App.Contacts.fetch();
},
error:function(model, xhr, options){
app.error(model);//custom handle for error
}
});

backbone:CRUD - (create)Post Data - save is not a function

i have created a backbone model like mentioned below
LoginModel = Backbone.View.extend({
initialize: function(){
},
defaults:{
username: 'XXXXX#XXXXX.com',
password: 'XXXXXXXXX'
},
urlRoot: 'https://XXXXX.portnumber/xxxxxx/xxxxxx/',
url: 'xxxxxxxxxx'
});
I am creating a login model instance and calling the method Save
var loginmodel = new LoginModel();
loginmodel.save({username:'xxxxxxx',password:'xxxxxxxx'},{
success: function(model, response){
console.log('success saved'+response);
},
error: function(model, response){
consoloe.log('failed saved'+response);
}});
Here i am getting an error
[06:22:39.742] TypeError: loginmodel.save is not a function
its not calling the backbone's save method to post the data to the server.
eh... I think you extend the wrong class, it should be a model, right?
LoginModel = Backbone.View.extend({
this line create a view, not a model. Backbone's View don't have save() method, so you got that error. You need:
LoginModel = Backbone.Model.extend({
and try other staff again.

Override sync method in backbone

I'm doing a model named person and i use parse.com javascript api. To send model to parse.com ì've created a my function send but i think it is wrong. I think that i have to override sync method with api parse.com and after use save method on the model created. It's right?
var Person = Backbone.Model.extend({
defaults: {},
initialize:function() {
console.log("inperson");
},
validate:function() {
console.log("validate");
},
send:function() {
var user = new Parse.User();
user.set("username", this.get("username"));
user.set("password", this.get("password"));
user.set("email", this.get("email"));
user.signUp(null, {
success: function(user) {
},
error: function(user, error) {
alert("Error: " + error.code + " " + error.message);
}
});
}
});
return Person;
});
Backbone only uses one sync method (Backbone.sync). All methods collections and models that are "talking" with the server goes through this one.
You can simply overwrite it by saying:
Backbone.sync = function(method, model, options) {
// method is send through methodMap witch is an object:
//var methodMap = {
// 'create': 'POST',
// 'update': 'PUT',
// 'patch': 'PATCH',
// 'delete': 'DELETE',
// 'read': 'GET'
//};
// model refers to the active model and you can use model.attributes to get all the attributes.
// So in here you can write your integration with parse.com and not change anything else while using backbone.
// Remember to trigger `sync` etc.
};
But I can see that parse.com allready have a REST-api so maybe this is not the solution.

Adding options to backbone.js model.save()

Is it possible to pass inside the options of the "save" method - a diffrent url/path for the request ?
The default urlRot for the model is --> urlRoot: "/users"
is it possible to do something like that:
this.model.save({
'userName': $('#userName').val(),
'password': $('#password').val()},{
url: "/users/login",
success: function(model, response, options) {
},
So the request, this time, will be sent to "/users/login" and NOT to "/users" ?
From the documentation:
urlmodel.url()
Returns the relative URL where the model's resource
would be located on the server. If your models are located somewhere
else, override this method with the correct logic. Generates URLs of
the form: "/[collection.url]/[id]", falling back to "/[urlRoot]/id" if
the model is not part of a collection.
So it looks as if you can provide your own url function on a model.
Example:
var MyModel = Backbone.Model.extend({
use_custom_url: false,
url: function() {
if (use_custom_url) {
return "/users/login";
} else {
return Backbone.Model.prototype.url.apply(this);
}
}
});

Categories