Fine Uploader concurrency issues - backbone.js

I'm using Fine Uploader to upload files directly to Amazon S3 (not relevant to the issue).
What I'm doing is to generate an "attachment" backbone.js model (which generates an unique ID), and passing that ID to the uploader via setParams in the submit event, in order for me to identify the attachment in the complete event and take appropriate actions.
The problem is manifesting when uploading multiple files at the same time (tried with 10 files). Fine Uploader apparently calls the submit callback too fast, and I am getting duplicate model IDs in the complete event.
If I add breakpoints to the submit event and do nothing, just hit "play" again, the concurrency problem is no longer present.
Part of my code is:
var self = this;
this.uploader.on('submit', function() {
var attachment = new Market.InboxPage.Models.Attachment(); // generates a new model with a unique ID
self.attachments[attachment.cid] = attachment; // self.attachments is a model collection
self.uploader.setParams({'cid': attachment.cid});
});
this.uploader.on('complete', function(event, id, file, response) {
self.attachments[response.metadata.cid].set({ // getting duplicate data here
filename: response.metadata.qqfilename,
key: response.metadata.key,
filesize: response.metadata.filesize
});
self.attachments[response.metadata.cid].updateInDom();
return false;
});

The issue is with your calls to setParams. You are effectively overwriting the params for all existing files with each call to setParams. Instead, you should be targeting a specific file with each call to setParams. setParams allows you to do this by specifying a file ID as a parameter to the setParams call. For example:
this.uploader.on('submitted', function(event, id, name) {
var attachment = new Market.InboxPage.Models.Attachment(); // generates a new model with a unique ID
self.attachments[attachment.cid] = attachment; // self.attachments is a model collection
self.uploader.setParams({'cid': attachment.cid}, id); });
Notice how I switched your logic to the submitted event, which is called after the file has been successfully submitted, and an ID is available.

Related

how to fetch the record from mongodb to part of html page automaticalyy without refreshing/reloading manually. using MEAN stack

Need some help reading Mean stack. I have a requirement like,
When a record is inserted into database, part of html page should get displayed with the new inserted record without reloading/refreshing manually.
Html page should get automatically updated with new record.
observations so far:
I am already using angularjs, nodejs and mongodb.
Using refresh() function, able to update part of hrml page manually.
I am to insert the record from html page to mongodb.
You should use websockets ( socket.io is a good option ).
In the route responsible for document insertion/update on the backend, you should emit a new_document signal with the document's body to all sockets in the site...
Example:
app.post('/api/posts', (req, res) => {
Post.insert(postBody).then(body => {
io.emit('new_document', body); // Broadcast to all websocket clients
res.json(body);
}).catch(err => {
console.error(err);
res.status(500).json({error: err.message});
});
});
Then, in the front-end, you should listen for the new_document event and call the refresh() function as callback or, even better, write a function to add just the new document.
Example:
socket.on('new_document', function (body) {
// ... code to add body to HTML ...
});

How does the data get updated in $HTTP.put

Currently I am working on an angularJS app. it reads an property file from a repository and output an xeditable table, so you can change all the properties.
The only question I have now is, how do I make http.put request to update data.
assume the properties file have:
var data = {'prop1' : 'this', 'prop2' : 'that'};
I currently have:
$scope.update = function(key,value){
$http.post('http://blabla.com/properties.json', $scope.data)
.success(function (data, status) {
//success code
})
So Assume I updated the prop1 from this to newProperty.
Is my code correct? does the file in remote repository get updated?
or do i have to do something like this
$scope.update = function(key,value){
$http.post('http://blabla.com/properties.json',
data: {
prop1: 'newProperty'
})
.success(function (data, status) {
//success code
})
I only changed prop1, do I need to include prop2 also inside the data bracket? What happen when i got like 30 properties, then how do I update only 1 of the values using Http.put?
thanks
That URL won't work. You need a server-side API that can handle file uploads. That's not possible with Angular alone.
e.g.
$http.put('http://blabla.com/properties_api', $scope.data);
Also you've written $http.post up there, and that will (and should) fail unless the data doesn't exist in your repository. Change it to put if you're updating, 'post' only if you're creating.
Generally, uploading the full object is the way to go, otherwise the server is likely to treat the lack of other data as an explicit intention to delete that data. If you've got 30 properties, upload all 30.
That depends on how your server code handles this upload. If you write it yourself it'll do whatever you want with the data you give it.
That being said, if you've got a lot of data it can be unfeasible to upload it all, so you can create multiple APIs that can each handle a particular type of data.
e.g.
$http.put('http://blabla.com/properties_api/prop1_handler', $scope.data);

$scope not updating after passing to new view with $location.path

I have a simple CRUD I put together with Angularjs. From a product list display I pass the user to a new view template for the "Create New" form.
The form processes fine and updates the database. I then pass the user back to the list display using "$location.path(url)".
For some reason when the list page displays, the changes do not appear in the $scope and you have to refresh the page to see the changes.
Sample code:
$scope.acns = acnFactory.query()
.$promise.then(function (data) {
$scope.acns = data;
});
the above displays the list of items.
$scope.createAcn = function () {
$scope.acn.isActive = true;
acnFactory.create($scope.acn);
$location.path('/acn');
}
The above POSTs the new product then redirects to the list page (/acn)
My assumption is that the list page will reprocess or watch the changes to the $scope but the view does not update.
The problem is most probably here:
$scope.createAcn = function () {
$scope.acn.isActive = true;
acnFactory.create($scope.acn);
$location.path('/acn');
}
creating a product most certainly consists in sending an HTTP request to the server. This is asynchronous. This means that acnFactory.create() returns immediately after the request has been sent. Not after the response has been received.
So, this code sends the request to create the product and immediately goes to the page which lists the products. The GET request sent to get the product list is thus sent almost at the same instant as the one used to create the new product. The two requests are handled concurrently by the server, and the returned list contains the list without the new product, which is being created in a separate transaction.
You need to wait for the response to come back, and make sure it's successful, before going to the product list. Assuming the service returns a promise, as it should do:
$scope.createAcn = function () {
$scope.acn.isActive = true;
acnFactory.create($scope.acn).then(function() {
$location.path('/acn');
});
};

Store is loaded twice after data.Model.save()

I have a grid with remote data (php/mysql/json) and use a form to insert records or to edit this data.
I use the api configuration of the proxy/store. I use MVC architecture.
So, all very simple (in pseudo code):
get selected model form grid or create model
frm.loadRecord()
frm.updateRecord()
frm.getRecord().save()
and all works fine, but I noticed in the browser console that after the POST (works fine, calls either the url configured with create or the url configured with update), the store calls (GET) the url configured with retrieve twice. These calls are identical.
So functionally all works fine and I could ignore it, but now I've noticed I want it fixed.
Can anyone help me where to look? Thanks in advance.
Details:
It's all really basic:
In the controller of the gridpanel:
updateRow: function (gridpanel) {
var sm = gridpanel.getSelectionModel();
var record = sm.getLastSelected();
this.showForm(record);
}
and
showForm: function (record) {
...
formpanel.show();
var frm = formpanel.getForm();
frm.loadRecord(record);
}
In the controller of the formpanel:
submit: function(frm) {
frm.updateRecord();
frm.getRecord().save();
}
When I remove the save action the GET requests aren't called, so this seems to trigger them.
In the store:
api: {
create: '../php/api/customers.php?request=create',
read: '../php/api/customers.php?request=retrieve&scope=summary',
update: '../php/api/customers.php?request=update',
destroy: '../php/api/customers.php?request=delete'
}
The screenshot:

Angular js way to download file and show loading screen using the $resource

I am using Angular js to show loading screen. It works for all the REST services call except REST service to download the file. I understand why it is not working because for download I am not making any service call using $resource; instead of that I am using normal approach to download the file therefore Angular js code doesn't have any control on start/finish the service request. I tried to use $resource to hit this REST service however I am getting the data from this service and in this case loading screen was working fine however not sure how to use this data to display to user to download in angular way. Following are required details. Please help.
Approach 1 using iframe approach:
/*Download file */
scope.downloadFile = function (fileId) {
//Show loading screen. (Somehow it is not working)
scope.loadingProjectFiles=true;
var fileDownloadURL = "/api/files/" + fileId + "/download";
downloadURL(fileDownloadURL);
//Hide loading screen
scope.loadingProjectFiles=false;
};
var $idown; // Keep it outside of the function, so it's initialized once.
var downloadURL = function (url) {
if ($idown) {
$idown.attr('src', url);
} else {
$idown = $('<iframe>', { id: 'idown', src: url }).hide().appendTo('body');
}
};
Approach 2 using $resource (Not sure how to display data on screen to download)
/*Download file */
scope.downloadFile = function (fileId) {
//Show loading screen (Here loading screen works).
scope.loadingProjectFiles=true;
//File download object
var fileDownloadObj = new DownloadFile();
//Make server call to create new File
fileDownloadObj.$get({ fileid: fileid }, function (response) {
//Q? How to use the response data to display on UI as download popup
//Hide loading screen
scope.loadingProjectFiles=false;
});
};
This is the correct pattern with the $resource service:
scope.downloadFile = function (fileId) {
//Show loading screen (Here loading screen works).
scope.loadingProjectFiles=true;
var FileResource = $resource('/api/files/:idParam', {idParam:'#id'});
//Make server call to retrieve a file
var yourFile = FileResource.$get({ id: fileId }, function () {
//Now (inside this callback) the response data is loaded inside the yourFile variable
//I know it's an ugly pattern but that's what $resource is about...
DoSomethingWithYourFile(yourFile);
//Hide loading screen
scope.loadingProjectFiles=false;
});
};
I agree with you that this is a weird pattern and is different of other APIs where the downloaded data is assigned to a parameter in a callback function, hence your confusion.
Pay attention to the names and the cases of the parameters, and look that there're two mappings involved here, one between the caller to the $resource object and the object itself, and another between this object and the url that it contructs for downloading the actual data.
Here are some idea's for the second approach, you could present the user with a link after the download has happened:
With a "data url". Probably not a good idea for large files.
With a URL like "filesystem:mydownload.zip" You'd first have to save the file with the filesystem API. You can find some inspiration on html5rocks

Resources