this.$refs.selectedImages.files.map is not a function - vue electron - file

I'm trying to use map function in my vue component. I have a file upload input that will accept multiple files. Since I'm working with electron, I can't pass directly the files to the backend of the app so I want to use the Array.prototype.map() function to get files path and proces them after passing the array using the ipcRenderer.send() function. Anyway I get always this error this.$refs.selectedImages.files.map is not a function how I can fix it?
Here is the actual code I'm trying
handleFiles() {
this.files = this.$refs.selectedImages.files.map( (file) => file.path ); //this will cause the error
}, //
processFiles() {
this.isLoading = true;
window.ipcRenderer.send('processFiles', this.files);
window.ipcRenderer.on('', (event, data) => {
console.log(ecent, data);
saveAs(data, 'processed.mfs')
});
}
UPDATE
To try solve the problem I'm looping the FilesList to extract the path of each file and then pass it using ipcRenderer. The problem is that I'm not able to get the message on the background.js and I'm not sure why.
this.$refs.selectedImages.files.forEach( (file) => {
this.files.push(file.path) // this will push into the array the path of each file
})
window.ipcRenderer.send('processFiles', this.files);
//background.js
import { ipcMain } from 'electron'
ipcMain.on('processFiles', (event, data) => {
console.log(event, data) // the message will not arrive
})

The FileList object is actually not an array, and has no .map method. But you can access the files like this:
const files = this.$refs.selectedImages.files;
for (var i = 0; i < files.length; i++) {
console.log(files[i]);
}

Related

Render Does Not Display Changes Until All Promises Are Resolved

I am trying to create a React component with a function append that behaves like console.log.
The current situation is that I have a list of URLs to download sequentially and would like to provide the user with progress in real-time.
Here is my component:
async componentDidMount() {
...
for (var i = 0; i < files.length; i++) {
this.downloadFile(files[i].url, files[i].filename);
}
...
}
append(text) {
var newMessage = this.state.message+"\n"+text;
this.setState({message: newMessage});
}
Where downloadFile is an async. I am using Electron and ipcRenderer.sendSync('download-file') returns are promise that resolves when the file has completed saving.
async downloadFile(url, filename) {
await ipcRenderer.sendSync('download-file', {url: url, filename: filename});
this.append("append file: " + filename);
}
When the program runs, React does not display the updated display message until the final ipcRenderer.sendSync promise resolves. I inspected the code and found that componentDidMount() and render() both complete but the component does not actually display any changes until the entire execution completes.
How can I get React to actually render the updated message?
Thank you for reading this.

how to lazy load only once in react

I am lazy loading service file dynamically on demand from a method, which gets called multiple times and i have to wait until i get response even though i had loaded that file before. Can i load it only once?
processData(serviceName: any, methodName: any) {
import(`./${serviceName}Service`)
.then(component =>{
var result = component.default[methodName] ? component.default[methodName]() : [];
}
})
.catch(error => {
console.error(`Model not yet supported` + error);
return null;
});
}
}
I have written above method to dynamically lazy load service file, it works fine. But processData() gets called many times(onchange of any control) and most of the times the files would have already imported once.
I do not want to load that file again. How or where can i implement this? I will not get serviceName parameter until home page route is called.
where can i lazy load import and use it forever in application?
You can do it by using a name-spaced object.
const servicesCache = {};
processData(serviceName: any, methodName: any) {
if (servicesCache[serviceName]) {
var result = servicesCache[methodName];
} else {
import (`./${serviceName}Service`)
.then(component => {
servicesCache[serviceName] = component.default[methodName] ? component.default[methodName]() : [];
var result = servicesCache[serviceName];
})
.catch(error => {
console.error(`Model not yet supported` + error);
return null;
});
}
}

Get Document information using word office add-in 2013

How to get the document information such as the author, created date and size using office word add-in 2013?
The Document.getFilePropertiesAsync method seems to only return the URL which is the file path.
Bizarre that the developers didn't add file size to getFilePropertiesAsync!
Fortunately, getFileAsync (link) provides the file size. You should be able to call this to simply get the size, save that attribute and close the file.
This works for me, I have it in my App component:
const [fileName, setFileName] = useState("");
const [fileSize, setFileSize] = useState(0);
useEffect(() => {
Office.context.document.getFilePropertiesAsync(function(asyncResult) {
if (asyncResult && asyncResult.value && asyncResult.value.url) {
const name = asyncResult.value.url.replace(/^.*[\\\/]/, "");
setFileName(name);
}
});
}, []);
useEffect(() => {
if (fileName) {
Office.context.document.getFileAsync(Office.FileType.Compressed, { sliceSize: 4194304 }, function(result) {
if (result.status == Office.AsyncResultStatus.Succeeded) {
// Get the File object from the result.
const file = result.value;
setFileSize(file.size);
file.closeAsync(() => {});
}
});
}
}, [fileName]); // Note: if both async file calls fire, one of them will fail.
The comment at the end refers to this error https://stackoverflow.com/a/28743717/1467365. The if (fileName) check in the 2nd useEffect hook ensures the file properties call completes before opening the file to get its size.
After fetching both you should be able to store them in a Context provider and access both attributes throughout your application.

How to loop through an object and push into an array

What I'm working with
angular2
firebase
What I have
A returned object
Each item in the object has a URL property
What I would like to do
Loop through each of the items in the object and get the URL property
Pass that into a firebase storage variable
Push the URL property into an array to make available for my HTML
note: I have this working by hard coding a url, I just need some assistance looping through the object to get the other urls in the object.
Component.ts
'this.imagesToDisplay' will return an object of object (image below)
this.activatedRoute.data
.subscribe((
data: { issueData: any, issueImageData: any }) => {
this.issueToDisplay = data.issueData;
this.imagesToDisplay = data.issueImageData;
this.testing(this.imageToDisplayArray);
});
Comnponent TS - Testing method
So this is hardcoded and pushes the hardcoded url into the array and displays correctly through databinding with the HTML. Cool. However, I would like to loop through the 'imagesToDisplay' object and get both returned urls.
testing(imageToDisplayArray) {
// this works with one url
var storage = firebase.storage().ref().child("image/-Kosd82P-bmh4SFetuf3/-Kosd8HhGmFiUhYMrlvw/30DD9F39-4684-4AA0-9DBF-3B0F0C3450A4.jpg");
storage.getDownloadURL().then(function(url) {
imageToDisplayArray.push(url);
console.log(imageToDisplayArray);
});
}
Any help here would be massively appreciated.
Note: I think this question here is what I'm trying to do, I'm just not sure how to integrate that into my current code. Any help would be awesome.
Stack Overflow question on firebase storage looping
UPDATE
So, I'm incredibly close now. I just have one issue. The code below loops through the returned data and extract the URL properties. I use the url properties to connect to the firebase storage and return the download URLs. Both of these are logged to the console! Awesome. I now have the URLs i needed! The issue I'm having is, it will only let me push these values to a local array. In this instance 'var array'. I need to push to an array that's outside of the 'activatedRoute' 'method'. Anytime I do, it returns as undefined.
this.activatedRoute.data
.subscribe((
data: { issueData: any, issueImageData: any }) => {
this.issueToDisplay = data.issueData;
this.imagesToDisplay = data.issueImageData;
var array = [];
data.issueImageData.forEach(image => {
// Reference to the image URL
var image = image.url;
// Firebase storage
var storage = firebase.storage();
// Path reference
var imagePathReference = storage.ref().child(image);
// Get Download URL
imagePathReference.getDownloadURL().then(function (url) {
console.log(url);
array.push(url);
})
});
});
I would recommend you to use the features rxjs provides you:
this.activatedRoute.data.switchMap(data => {
let parsedData = {
issueToDisplay: data.issueData,
imagesToDisplay: data.issueImageData
}
let imageUrls$ = data.issueImageData.map(image => {
var imagePathReference = storage.ref().child(image);
return Observable.fromPromise(imagePathReference.getDownloadURL())
});
return Observable.forkJoin(imageUrls$).map((...urls) => {
return Object.assign(parsedData, { urls });
})
}).subscribe(data => {
/*
data looks like this:
{
issueToDisplay: any,
imagesToDisplay: any,
urls: string[]
}
*/
});
If I'm correct, you're looking for a solution to map an array-like object of objects to an actual array of objects.
Here is a way to do just that:
var object = {
'0': {
"url": "url1",
"name": "obj1",
"data": 1234
},
'1': {
"url": "url2",
"name": "obj2",
"data": 5678
},
'length': 2
}
var sliced = Array.prototype.slice.call( object, 0 );
console.log(sliced)
Couple remarks:
If you wonder how this works, check this post.
Alternative syntax that you could encounter looks like [].slice.call()
If you want to perform array-like operations, you can probably do that right away with Array.prototype.<METHOD>.call(object, <CALLBACK>
For example:
Array.prototype.map.call(object, function(el) { // return your enhanced element })
So, this works. Not entirely sure how clean it is. But it works.
this.activatedRoute.data
.subscribe((
data: { issueData: any, issueImageData: any }) => {
this.issueToDisplay = data.issueData;
this.imagesToDisplay = data.issueImageData;
var localImageArray = [];
data.issueImageData.forEach(image => {
// Reference to the image URL
var image = image.url;
// Firebase storage
var storage = firebase.storage();
// Path reference
var imagePathReference = storage.ref().child(image);
// Get Download URL
imagePathReference.getDownloadURL().then(function (url) {
localImageArray.push(url);
})
this.getIssueImageArray(localImageArray);
});
});
}
// Get Image Array
getIssueImageArray(array) {
this.imageToDisplayArray = array;
}

Function stops to work when $http is inside it

I've got a pretty odd issue if I ask myself.
Currently I've got a function in my view which is something like this:
<h3 ng-click="{{ vm.open(item.info) }}"> {{ item.title }} </h3>
and a function in my controller looking like this:
open = (url) => {
console.log(url);
}
This function works as intended it writes out the slug of the item from the view. But the issue comes when I try to add my API service or a simple $http.get() call. It seems to break the entire function because if I add this to the function:
open = (url) => {
console.log(url);
result.getOpportunity(url).then(result => {
res = result.data;
var modal = res.title;
console.log(modal);
});
}
Nothing gets printed out in the console. not even the first console.log() that worked so pretty just seconds ago.
Can anyone tell me what is going on? I don't get any error in either console or terminal but something do seem to be broken somewhere.
Worth mentioning is that I'm using an yeoman generator called Angular fullstack which uses Babel.
If I look into my gulp serve:ed .controller.js file that when I use the function that works. the single console.log line my file contains this:
this.open = function (url) {
console.log(url);
};
and when I use the longer function which doesn't work this is in the ouputted controller.js:
on the line where the function that works was this is now: _initialiseProps.call(this); and later on this function:
var _initialiseProps = function _initialiseProps() {
var _this2 = this;
this.open = function (url) {
console.log(url);
_this2.result.getOpportunity(url).then(function (result) {
res = result.data;
var modal = res.title;
console.log(modal);
});
};
};
so Babel rewrites pretty much. but the most peculiar thing I noticed was that if I call _initialiseProps.call(this); explicit via the console I get returned undefined which do make some sense because the function _intiliaseProps() function does not contain a function called call()
but when I call _initialiseProps(this); from the console I get an error returned with this:
post.controller.js:29 Uncaught TypeError: Cannot set property '_checkURLforHTTP' of undefined(…)
Which is kinda funny or i dont know.. tearing my hair right now. Anyway, the _checkURLforHTTP function contains this in the code before babel had it's thing going:
_checkURLforHTTP = (img) => {
if (img.indexOf('http://') > -1 || img.indexOf('https://') > -1 ) {
return 'url("' + img + '")';
} else {
return 'url("http://HARDCODED-URL-HERE' + img + '")';
}
};
and the same function in the babel-processed file is the following:
var _initialiseProps = function _initialiseProps() {
var _this2 = this;
this._checkURLforHTTP = function (img) {
if (img.indexOf('http://') > -1 || img.indexOf('https://') > -1) {
return 'url("' + img + '")';
} else {
return 'url("https://HARDCODED-URL-HERE/' + img + '")';
}
};
};
Obviously it is something i'm not doing right, but i dont seem to understand what it is im doing wrong. I think I've managed to break it down into a click function in the view using $http.get();

Resources