How to stop models being overwritten on refresh in backbone.js - backbone.js

I have a collection of user models that starts with basic data:
[
{'_id': 1, 'username': 'Jamie', 'image': 'jamie.jpg'},
{'_id': 2, 'username': 'Andrew', 'image': 'andrew.jpg'},
{'_id': 3, 'username': 'Kerry', 'image': 'kerry.jpg'}
];
but when a user clicks on the collection models view I load more data into the model so then I can create a profile view of the data:
{
'_id' : 1,
'username' : 'Jamie',
'image' : 'jamie.jpg',
'age' : 21,
'country' : 'UK'
};
I have set it up so that when the full profile data has been loaded it wont be fetched again to save on GET requests.
However I have a refresh button on the main users view so and when I refresh the data all the loaded profile data is gone and I am required to make GET requests to get the information back.
I was wondering how I would go about solving this problem.
More details:
The purpose of the refresh button is to add new online users. I want this button so users who want to see new data will use this instead of refreshing the whole page.
The problem with wiping the loaded data is when a user goes back to the profile (which will happen a lot because I am going to add the ability to chat on each profile which requires the user to be on that users profile) there is an unnecessary GET requests because the data has already been loaded previously in the users session.

Running .fetch({add:true}) would avoid overwriting existing models, but then you'd be left with duplicates. To weed out duplicates and add new models to the collection, you'll need to combine .fetch({add:true}) with a custom parse() function:
parse: function(response) {
var client_ids = _.map(allUsers,function(user){ return user.get('id'); });
response = _.filter(response,function(user){
// true if user is not already in collection
return _.indexOf(client_ids,user.id) < 0;
});
return response;
}
I don't have any way to test this right now, so please try it out and let me know if it works.

Related

Coldfusion - Refreshing Page When A Database Record Updates

Good day,
Let me describe my problem :
Scenario :
User 1 has a coldfusion webpage, containing 6 alerts as html elements populated using a database. User 1 is constantly monitoring this page for changes.
A user on a different computer (different session) logs into a admin console and add's a 7th element and inserts it into the database.
The database contains a field that changes from 0 to 1 as soon as an alert is added and inserted into the database.
The webpage of User 1 not has to dynamically refresh or update with the 8th alert.
Problem :
I am struggling to run a async loop that queries the database permanently for the record that tells it there is a change, while not freezing the rest of the page.
Solution :
I need to run a cfquery to check the isUpdated field in the database.
That cfquery needs to be run every minute.
As soon as the cfquery returns a 1, the page should refresh which in turn will populate the new alert as well.
Can be done through sockets, and you do not have to check the availability of a new record every minute.
You can also do it with javascript/jquery:
<script>
var lastAlert = '#lastAlert#'; //last at the time of loading the page
setInterval(function() {
lastAlert = isUpdated(lastAlert);
}, 60000);
function isUpdated(lastAlert){
res = lastAlert;
$.ajax({
url: 'checkAlerts.cfm', //in this file do check for changes in the database. should return the number of the last alert
type: 'POST',
data: {lastAlert:lastAlert},
cache: false,
success:function(res){
if(res > lastAlert){
//your code if there is a new entry
alert('a new entry has been added');
}
}
});
return res;
}
</script>
I did not check the code! But I hope you understand how to proceed.

Unable to display $scope in view

I am querying a database and retrieving all the images belonging to the logged-in user, here is that code in uploadController:
UserImage.get($scope.user_id)
.success(function(data) {
$scope.userArray = data;
$location.path('/display');
});
I can console log the value of data and it is (first document):
0: Object
__v: 0
_id: "563bd07c7a49a7ac9ae1c513"
date: "2015-11-05T21:56:12.312Z"
gallery: "first gallery"
name: "1b0f6d56-9ed6-4412-a0d6-897a25fb3a84-460x360.jpeg"
user: "563bd0527a49a7ac9ae1c512"
so now I test that the target view (display.html) can receive the $scope.data:
<<div>{{userArray[0].name}}</div>
The $scope.userArray is not available to the display.html.
I tested the $scope in plunker and it worked ok:
http://plnkr.co/edit/q5XXnfl3JxkRdG0jLyps?p=preview
So I am a bit stumped.
first of all you should use ".then" instead of ".success" to use to promise system. If you want to know more about it
And i think your problem is also connected with $location.path('/display'); you ask your application to change location as soon as you get the answer, so it is probably loading another controller and stopping with your current one.

ExtJs Model Proxy vs. Store Proxy

OK, I'm stuck on what should be a basic task in ExtJs. I'm writing a simple login script that sends a user name and password combination to a RESTful web service and receives a GUID if the credentials are correct.
My question is, do I use a Model Proxy or a Store Proxy?
To my understanding, Models represent a single record, whereas Stores are for handling sets of data containing more than one record. If this is correct then it would seem that a Model proxy is the way to go.
Following Sencha's documentation at http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.data.Model the code would look something like this:
Ext.define('AuthenticationModel', {
extend: 'Ext.data.Model',
fields: ['username', 'password'],
proxy: {
type: 'rest',
url : '/authentication'
}
});
//get a reference to the authentication model class
var AuthenticationModel = Ext.ModelManager.getModel('AuthenticationModel');
So far everything is OK, until the next step:
//Use the configured RestProxy to make a GET request
AuthenticationModel.load('???', {
success: function(session) {
console.log('Login successful');
}
});
The load() method for the Model class is a static call expecting a single unique identifier. Logins typically depend upon two factors, username and password.
So it appears Store proxies are the only way to validate someone's username and password credential combination in ExtJS. Can someone verify and explain? Any help to understand this would be greatly appreciated.
You just need to know the following:
The store will use it's own proxy if you configured one for this
instance and if not he takes the proxy from the model.
So you can easily go with two proxy configurations to enable the multi-CRUD operations on the store and the single-CRUD operations on the Models. Note the the static load method of the Model expects the model id because it is supposed to load a model by just one Id (yes, composite keys are not supported). You will also have to fetch the model instance in the callback (As you did).
Back to your Username/password problem
You may apply your session Model with a custom 'loadSession' method
loadSession: function(username,password, config) {
config = Ext.apply({}, config);
config = Ext.applyIf(config, {
action: 'read',
username: username,
password: password
});
var operation = new Ext.data.Operation(config),
scope = config.scope || this,
callback;
callback = function(operation) {
var record = null,
success = operation.wasSuccessful();
if (success) {
record = operation.getRecords()[0];
// If the server didn't set the id, do it here
if (!record.hasId()) {
record.setId(username); // take care to apply the write ID here!!!
}
Ext.callback(config.success, scope, [record, operation]);
} else {
Ext.callback(config.failure, scope, [record, operation]);
}
Ext.callback(config.callback, scope, [record, operation, success]);
};
this.getProxy().read(operation, callback, this);
}
Now call this instead of load.
I found it in the documentation of sencha App Architecture Part 2
Use proxies for models:
It is generally good practice to do this as it allows you to load and
save instances of this model without needing a store. Also, when
multiple stores use this same model, you don’t have to redefine your
proxy on each one of them.
Use proxies for stores:
In Ext JS 4, multiple stores can use the same data model, even if the
stores will load their data from different sources. In our example,
the Station model will be used by the SearchResults and the Stations
store, both loading the data from a different location. One returns
search results, the other returns the user’s favorite stations. To
achieve this, one of our stores will need to override the proxy
defined on the model.

Using backbone with sequelize/postgres

I'm working on creating a model in backbone to interact with my postgres database. I'm using backbone.js for the client side and node.js/sequelize.js for the server side. The code given in the backbone tutorial says this:
var UserModel = Backbone.Model.extend({
urlRoot: '/user',
defaults: {
name: '',
email: ''
}
});
Here they are interacting with a users sql database using a RESTful url (I have no idea what that is). Does anyone have any ideas how I can refer to my postgres table? I am beyond confused and have no idea what's going on (this is all really new to me)
Thanks.
A RESTful URL is just a URL for a webservice that uses RESTful principles. Google can explain that better than I can here, but the basic idea is to integrate the various REST "verbs" (GET, POST, DELETE, etc.) in to the API. For instance, here's a set of RESTful verbs + urls for an imaginary user API:
GET /user - returns a list of users
POST /user - creates a new user
DELETE /user/5 - deletes the user with ID 5
PUT /user/5 - updates/edits the user with ID 5
Backbone works particularly well if your server-side is designed similarly, but it's not a requirement.
If your server-side API isn't RESTful, you just need to override certain methods on your Models and Collections (most likely destroy, fetch, save, url, parse, sync, and toJSON) to do whatever is appropriate for your server.
For instance, you might want to override the url method of your model to make it return your server's (unRESTful) URL:
url: function() {
return 'www.example.com/some/very/not/RESTful/' + this.id + '/URL/example';
}
Or, if your server returns your objects with an "envelope", for instance:
{
type: 'envelope',
payload: {
type: 'user',
name: 'Bob',
id: 5,
}
}
you can modify parse to strip it out:
parse: function(original) {
return original.payload;
}
As for "how do I refer to my postgres table", if you override the appropriate methods, then call the appropriate Backbone action methods (fetch/save/destroy) on your models and collections, Backbone will make AJAX requests to the URL you define in your url override. Your server can then use any language you want to interpret that request and perform the appropriate operation on your PostgreSQL database.

Callbacks in views

This may be more of a question around design pattern - I hope it makes sense.
I am using backbone - am developing a relatively simple app where user can add requests (where the request model is simply heading, description and price). The only requirement to add the requests is that a user is 'logged in'.
However I wish that the user 'adds' the request before checking if the user is logged in (remove one barrier). By that I mean that the user fills the form in, if not registered they have to register and then the request is just sent, if they were logged in it would just be sent. So initially the 'add request' view is rendered, when save is triggered this will call the save on the model which calls the ajax request on the server. The response will either return true (the user was logged in and the request added) or false (the user was not logged in).
So assuming that the user was not logged in - then I would wish to render a new view 'register' which has the option for the user to switch to 'login' (another view). So User in theory could go from
Request (save) -> Register -> Login -> Request (save)
So presuming that the user then registered (filled in the form which then called the registers view save method which then called the registers model save and returned ok). I would then wish to once again call the 'request' save method once again (as now the user would be logged in). However I do not want the register/login tied to the Request view - as in theory a new view (lets say I had a sent message view) would want similar functionality e.g. try and make the request, if failed switch view to register - perform save and then call some callback.
So the question is what is the right way to do this?
1) Do I create some closure inside the request view referencing the 'save' function and store it in a global to be called by register/login onsuccess?
2) Create a closure as above and pass that to the register etc (and if so how would I pass this given register/login is a view).
3) Pass a reference to 'this' of the request view?
So far all I have is, so in the else I would render the 'register' view but would love to know best way to do this without it getting very ugly?
save : function(event){
if(this.model.isValid() == true) {
this.$("#general_error").hide();
this.model.set({'formattedPrice' : TB_H.formatPrice(this.model.get('currency'), this.model.get('price'))});
self = this;
this.model.save(this.model.toJSON(), {
success: function(m, y) {
if(y.status == true) {
self.model = new TB_BB.Request();
Backbone.ModelBinding.bind(self);
Backbone.Validation.bind(self);
$('#add-offer-button').show();
} else {
if(y.errors[0] == 'not logged in') {
this.$("#general_error").html('You are not logged in');
this.$("#general_error").show();
} else {
_.each(y.errors, function(key, val) { this.$("#general_error").html(key) });
this.$("#general_error").show();
}
}
}, error : function(m,y) {
this.$("#general_error").show();
this.$("#general_error").html("Something bad happened - please try again")
}
}
);
}
Greatly appreciate any help!
I noticed this after asking a similar question, which I just deleted. I'm thinking this isn't the way most people are doing it in backbone.
what I did instead was pass my different routes to the same method and if the ids were not null, I'd call the route.
So I have a view
base_view = Backbone.Views.extend({
initialize: function(id,a_id,b_id){
this.id = id;
this.a_id = a_id;
this.b_id = b_id;
Myapp.data = new Myapp.Model.Base();
Myapp.data.url = '/data_url/'+id;
Myapp.data.fetch(Myapp.data, {
success: function(response){
// i have some nested collections, and models so i fill those in here
Myapp.mainModel = new First_Child_Collection(response.attributes.first_child_array);
}, error: function(){
alert('oops couldn't get data');
}
});
Myapp.data.bind("fetched",this.render,this);
},
render: function(){
new Main_View();
new Sub_View_1(this.id);
new Sub_View_2(this.a_id);
new Sub_View_3(this.b_id);
}
});
Then in my routes, rather than having a new route for each, I have
routes: {
"app/new": "new",
"app/:id/edit/a/:a_id/b/:b_id": "edit"
}
edit {
new base_view(id,a_id,b_id);
}
I'm not sure if this is perfect, but I think it is DRY'r than the other options. I just check that a_id or b_id are not undefined before passing those views.
Hope it helps.

Resources