In OfficeJS if we use the addFileAttachmentAsync function for multiple files, the callback runs only for one - outlook-addin

The basic implementation of the addFileAttachmentAsync is as follows:
Office.context.mailbox.item.addFileAttachmentAsync(
fileURL,
selectedAttachment.name,
{},
(result) => {
console.log('error or success')
},
);
Now this works. If I call this multiple times for multiple files, it works. All the files get uploaded. But one problem. The callback gets fired only once. Let's say there were two files and both files throw errors. I'll be able to read the error of only one file. How can I fix this and make the callback run for all executions separately?

Related

Flux File upload validation - file type

I am new to reactive programming. I am using flux for file upload. I need to make sure that all the files uploaded are of a specific type. If not I need to fail the request.
File.flatmap(input-> validate file())
.flatMAp(output->uploadtoazur())
My problem is when the second file is unacceptable type the first file has been processed. I want validateFile to scan all file and then do processing further
Basically if you want to process all the files at a time, not one-by-one, you should first collect them, since you're dealing with Flux. So, you can achieve it with collectList() on your Flux
And then, having List of your files, you can validate and process them. Here is an example of making your validation with handle()
On your Flux of files:
.collectList() // collect all files to List
.handle((files, sink) -> {
// validate all your files here, for example, using regular Stream API with allMatch()
...
if (allValid) {
// return these files if all files are valid
sink.next(files);
} else {
// throw Exception if some files are not valid
sink.error(new Exception("Some files are not valid"));
}
})
...
// further processing
This is one of the many possible ideas how to achieve what you want.
P.S. Actually you should have provided more code and format it properly.

generating table from *.geojson

I'm generating a HTML-table with data from a geojson-file using leaflet. It works fine, but only if I do not delete the "alert" from the following code. Otherwise the data are displaied without table. How to solve this?
$.ajax({url:"wind.geojson"}).done(function(data) {
var data = JSON.parse(data);
L.geoJson(data,
{pointToLayer: MarkerStyle1});
});
alert();
function MarkerStyle1 (feature,latlng) {
...
document.writeln ("<td width='40'><div align='center'>" ,feature.properties.title, "</div></td>\n");
...
};
I do not see any possibility here to upload a file, it's 200kb. It's to find here: 1 The file works well, when I show the objects on a map.
2 shows on older version of the site, where the table is generated with php (done by a friend, I do not use php).
Perhaps it is a problem, that I do not have a "map", no "map.addLayer()" in this code!?
I now realized that the problem is caused by the asynchronous working of AJAX. I changed the code to
$.ajax({url:"wind.geojson", async: false})
Now it is working without the "alert()"-line!

Limiting simultaneous downloads using RxAlamofire

Given my App will download files from a server and I only want 1 download to be progressed at the same time, then how could this be done with RxAlamofire? I might simply be missing an Rx operator.
Here's the rough code:
Observable
.from(paths)
.flatMapWithIndex({ (ip, idx) -> Observable<(Int, Video)> in
let v = self.files![ip.row] as! Video
return Observable.from([(idx, v)])
})
.flatMap { (item) -> Observable<Video> in
let req = URLRequest(url: item.1.downloadURL())
return Api.alamofireManager()
.rx
.download(req, to: { (url, response) -> (destinationURL: URL, options: DownloadRequest.DownloadOptions) in
...
})
.flatMap({ $0.rx.progress() })
.flatMap { (progress) -> Observable<Float> in
// Update a progress bar
...
}
// Only propagate finished items
.filter { $0 >= 1.0 }
// Return the item itself
.flatMap { _ in Observable.from([item.1]) }
}
.subscribe(
onNext: { (res) in
...
},
onError: { (error) in
...
},
onCompleted: {
...
}
)
My problem is a) RxAlamofire will download multiple items at the same time and b) the (progress) block is called multiple times for those various items (with different progress infos on each, causing the UI to behave a bit weird).
How to ensure the downloads are done one by one instead of simultaneously?
Does alamofireManager().rx.download() download concurrently or serially?
I'm not sure how it does, so test that first. Isolate this code and see if it does execute multiple downloads at once. If it does, then read up on the documentation for serial downloads instead of concurrent downloads.
If it downloads one at a time, then it means it has something to do with your Rx code that triggers the progress bar update issue. If it doesn't download one at a time, then it means we just need to read up on Alamofire's documentation on how to download one at a time.
Complex transformations and side effects
Something to consider is that your data streams are becoming more complex and difficult to debug because so many things are happening in one stream. Because of the multiple flat maps, there can be a lot more emissions coming out affecting the progress bar update. It is also possible that the numerous flat maps operations that acquired an Observable are the cause for the multiple triggering of the updates on the progress bar.
Complex data streams
In one data stream you (a) performed the network call (b) updated the progress bar (c) filtered finished videos (d) and went back to the video you wanted by using flatMapWithIndex at the start to pair together id and the video model so that you can return back to the model at the end. Kind of complicated... My guess is that the weird progress bar updates might be caused by creating a hot observable on call of $0.rx.progress().
I made a github gist of my Rx Playground that tries to model what you're trying to do.
In functional reactive programming, it would be much more readable and easier to debug if you first define your data streams/observables. In my gist, I began with the observables and how I planned to model the download progress.
This code will avoid the concurrency issues if the RxAlamofire query downloads 1 at a time, and it properly presents the progress value for a UIProgressBar.
Side note
Do you need to track the individual progress downloads per download item? Or do you want your progress bar to just increment per finished download item?
Also, be wary with the possible dangers of misusing a chain of multiple flatMaps as explained here.

How can I pass a variable into the then clause of a promise

I think I must have a fundamental misunderstanding somewhere. I'm using Aurelia to upload files to the server. The first call creates a folder for the files and when that finishes I want to upload the files. My code looks like this:
if(myFiles.length !== 0 && myFiles !== null){
this.data.createContainer(refNo)
.then((response) => {
this.data.upLoadFiles(refNo, myFiles)
});
At the if statement myFiles contains the file list. However when it gets to the this.data.upLoadFiles statement, myFiles is undefined. I'm not sure the right way to do this.
I fell victim to a less than complete understanding of promises. The code to clean up after saving was executing before the promise was resolved.

durandal event not working properly

I am using durandal to pass messages between view models. So i used below code to send message
return (datacontext.getData("Test, testData))
.then(app.trigger('FireEvent', `dataObsArray`))
.fail(queryFailed);
Then i use below code to retrieve message
app.on('FireEvent').then(function (data) {
testObsArray(data);
});
But when i put breakpoint in the app.on on this line testObsArray(data);
it doesnt stop there. The debugger stops on line app.on('FireEvent').then(function (data)
I dont get data. Why is it so? When i pass data to dataObsArray , there are 10 records.
I am not sure why i am not getting any data. Where i am wrong? I am really new to Durandal so extremely sorry if i am not able to explain this properly and do let me know if you need more clarification.
Your problem is here;
.then(app.trigger('FireEvent', `dataObsArray`))
The way that will resolve is to call app.trigger, get the result, and pass that as the next step in the chain to then(), which is unlikely to be what you want. You need to wrap that in an anonymous function so that then() can call it after the dataContext call.
return (datacontext.getData("Test, testData))
.then(function(data) {
app.trigger('FireEvent', data?) //This depends on what getData returns
})
.fail(queryFailed);