Download files with AngularJS - angularjs

I need to allow the user to download an array of bytes I get from a REST api.
The backend api return something like this:
GET /api/files/123
{
filename: 'myfile.pdf',
file: [base64]
}
On my html I have something like this:
<div ng-click="click()">Download</div>
And somewhere in my controller I have:
$scope.click: function (){
$http.get('/api/files/123',{headers:{x-security:'some_sec_token'}})
.then(
function (response){
// do something to return the array of bytes
},
function (error){
console.log(error);
}
);
}
I'm stuck on how to return the array of bytes with the Content-Disposition header using the filename returned by the api.

If you want to create a file using the array of bytes as content then you can use this library:
https://github.com/eligrey/FileSaver.js/blob/master/FileSaver.js
Import that library in you angular project and then try this:
var blob = new Blob(<arrayOfBytes>, {type: <yourFileType>});
saveAs(blob, [nameToSave]);
yourFileType should be something like "image/jpg" or similar depending on your file type
nameTosave should have the file type as well.. example: "myFile.pdf"
Hope it helps.
Cheers

Related

How could I fetch File to server and use its response to display on Svelte Frontend?

In the Svelt File:
import { FileDropzone } from "attractions";
File-Dropzone.svelte:
async function acceptUpload(e) {
...some code...
const fetchResponse = await fetch('http://localhost:5000/upload', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({"document-array": fileParagraphs})
});
let jsonedResponse = await fetchResponse.json();
--> let responseArray = JSON.parse(jsonedResponse); - I want to use this in the main Svelte to display some content after user uploaded a file.
So the goal is to display the content from fetch made to FastAPI server. Fetch sends file Content that I get via FileDropzone from "attractions" for Svelte. I could only print response in the console as the function situated in another Svelte File.
I tried to transfer response to main Svelte and then update content on Web Page. But I don't know how to get variable's value from another Svelte file's function...
I tried to export & import, but it seems impossible since the variable situated in the function.
You could get files from FileDropzone (or e.g. form) straight in the Main Svelte File using bind:files
Move your functions to the main File.svelte
Create a variable with an empty array to save files into it
Add Bind to your <FileDropzone Tag in your case (or <Form)
Now your new variable is filled with files!
4.1) If needed, get bind value (files) via {} - then you could show this variable on screen. That´s pretty much how you render value on the page.
Then you should have code look alike:
let files = []; //<-- Create a new array initially.
import { FileDropzone } from "attractions";
function fetchServer(--> files array here <--) {
//---your func body for fetching
}
</script>
<main>
<FileDropzone bind:files/> //<-- Now our files will go into a new array "files"
<p>{fetchServer(files)}</p> //<-- Then we render its value on the Web Page.
</main>

How to attach pageObjects to multiple browser instances in a Single test script in protractor

I'm trying to use Page objects with multiple browser instances in a single test script.. i got a solution but i'm looking for some better solution.
My PageObject file
var facebook=function(browserInstance){
browserInit=browserInstance;
element=browserInit.element;
this.email=function(){
return element(By.id("email"));
}
this.password=function(){
return element(By.id("pass"));
}
this.submit=function(){
return element(By.xpath("//input[#aria-label='Log In']"));
}
}
module.exports=facebook;
usage of Page objects with multiple browser
this.When(/^User entered the text in the email field$/,async function(){
// for using in browser2 i need to initialize it
page2=new facebook(browser2);
console.log(await page2.title()+" browser2");
await page2.search().sendKeys("testing");
browser2.sleep(3000);
//for using in first browser i need to initialize it
page1=new facebook(firstBrowser);
console.log(await page1.title()+" browser1")
await page1.email().sendKeys(testData.Login.CM[0].Username);
screenshots.takeScreenshot("newScreenshot");
firstBrowser.sleep(5000);
//now if i want again in browser2.. i need to initialize the page2 with browser instance again like below
page2=new facebook(browser2);
console.log(await page2.title()+" browser2");
});
how to overcome this initialization every time
I think you can do something like this in your conf.js file
baseUrl: 'http://localhost:8081',
onPrepare: function() {
global.browsers = {
a: browser,
b: browser.forkNewDriverInstance()
};
}
And inside the spec file or the step definition file, you can have
this.When(/^User entered the text in the email field$/,async function(){
let browser1 = browsers.a;
let browser2 = browsers.b
//do your stuff
.
.
.
.
.
});

Is there a way to dump a thousand images somewhere and extract them using REST Api?

Here is the thing:-
I have over a thousand images saved locally in my mac. I have a landing page that mocks an ecommerce deal site. It would be tedious to have to manually type in the src url in the img tag for a thousand pictures. Thus, i thought i could somehow have this images dumped in a cloud storage or something and use REST api get method to extract these images in a response.data. Then assign it to a $scope variable and use ng-repeat to bind the images in my landing page view. Is this possible? If not, what are the alternatives? SQL database?
Appreciate your help. P.S. I am totally a beginner at web development.
Install node.js. It's Javascript for a server which should make it pretty easy since you already know Javascript.
On a Mac, you can install node like this:
brew install node
Use this node.js code (credit to codepedia.com, tweaked a little by me):
//include http, fs and url module
var http = require('http'),
fs = require('fs'),
path = require('path'),
url = require('url');
imageDir = './images/';
//create http server listening on port 3333
http.createServer(function (req, res) {
//use the url to parse the requested url and get the image name
var query = url.parse(req.url,true).query;
pic = query.image;
if (typeof pic === 'undefined') {
getImages(imageDir, function (err, files) {
var imageList = JSON.stringify(files);
res.writeHead(200, {'Content-type':'application/json'});
res.end(imageList);
});
} else {
//read the image using fs and send the image content back in the response
fs.readFile(imageDir + pic, function (err, content) {
if (err) {
res.writeHead(400, {'Content-type':'text/html'})
console.log(err);
res.end("No such image");
} else {
//specify the content type in the response will be an image
res.writeHead(200,{'Content-type':'image/jpg'});
res.end(content, "binary");
}
});
}
}).listen(3333);
console.log("Server running at http://localhost:3333/");
//get the list of jpg files in the image dir
function getImages(imageDir, callback) {
var fileType = '.jpg',
files = [], i;
fs.readdir(imageDir, function (err, list) {
for(i=0; i<list.length; i++) {
if(path.extname(list[i]) === fileType) {
files.push(list[i]); //store the file name into the array files
}
}
callback(err, files);
});
}
Run this from the command line to start you new image server (assuming you named the file "server.js"):
node server.js
You should see this text appear on the command line:
Server running at http://localhost:3333/
You can quickly test it by going to this address in your browser and you should see a JSON object showing you an array of all the filenames in the "./images" directory. By the way, this program assumes you're putting the images folder in the same directory as "server.js". You can put the images directory anywhere and just change the path of the variable "imageDir".
Now you can load the list of files from Angular using this code in your controller:
$http.get("http://localhost:3333", function(data) {
$scope.images = data;
});
In your view, you can now use an ng-repeat like this to display all the images:
<div ng-repeat="image in images" style="padding: 8px">
<img src="http://localhost:3333/image={{ image }}">
</div>
Note: this will work if you run it locally on your Mac or if you upload all the images to a server on which you can use Node.js.

$update not a function using $resource?

I want update document using two ids using $resource.my api root is like this
$resource("http://192.168.0.2:3060/product/:subid/:productid",{"subid": "#subid"},{"productid": "#productid"},{update:{method:"PUT"}});
i got the error like this.
subproduct.$update is not a function
My Factory Like this:
ZustShopFactoryModule.factory("SubMenuItemFactory",function($resource,$q,RES_URL){
var subproductinfo=[]
var subproductresource=$resource("http://192.168.0.2:3060/product/:subid/:productid",{"subid": "#subid"},{"productid": "#productid"},{update:{method:"PUT"}});
return{
updatesubproductItem:function(SubMenuItem,idx){
var subproduct=new subproductresource(SubMenuItem,SubMenuItem.subid);
console.log(subproduct)
console.log(SubMenuItem.subid)
console.log(SubMenuItem._id)
subproduct.$update({"subid":SubMenuItem.subid,"productid": SubMenuItem._id},function(data){
console.log(data)
subproductinfo[idx]=data;
console.log("Updated...")
},function(){
console.log("Not Updated...")
})
}
}
})
please help me how to do this?
Try putting update in quotes like so:
$resource("http://192.168.0.2:3060/product/:subid/:productid",
{"subid": "#subid"},{"productid": "#productid"},
{
'update': {method:"PUT"}
});
You also might be using new wrong. new usually takes one argument which is the resource to be created as a JSON object. If the above fix doesn't work, what is the output of your console.logs?

Get a .js file dynamically rather than importing them

I have a small app that gives support to 30+ languages. I used react-intl to achieve my task. In react-intl I got to import every locale where every local file is around 7-8kbs, whereas I want to reduce these unnecessary imports and want to import only one file
app.js
import {IntlProvider, addLocaleData} from 'react-intl'
import ca from 'react-intl/locale-data/ca'
import cs from 'react-intl/locale-data/cs'
...
import hu from 'react-intl/locale-data/hu'
import id from 'react-intl/locale-data/id'
import enMessages from '../assets/translations/en.json'
Translations.getLocale('fr').then(function(localeData){
addLocaleData(localeData);
console.log("localeData");
console.log(localeData); //Code instead of array of objects
}, function(status) {
alert('Something went wrong.');
});
Now the ca, cs,hu etc. contain array of objects returned from the respective js files.
I tried using XHR but instead of returning the array of objects, I get the code that is written in the .js file. Is there any way I can dynamically import the js file or if I can get the array of objects from the code returned by XMLHttpRequest.
Translations.js
getLocale: function(lang, successHandler, errorHandler){
var url = 'http://localhost/img/' + lang + '.js';
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
//xhr.responseType = 'application/javascript';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
resolve(xhr.response);
} else {
reject(status);
}
};
xhr.send();
});
//return message;
}
If I understand you correctly, you retrieve the javascript code, which you want retrieve the output from.
One solution is to use eval, although this is generally not considered very secure. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
You can also make the code an automatically executing function that puts the output on a global variable, and access it from there. Append the content of the js file as a script in the head tag, and make the file contain something like.
myGlobalVar = (function() {
return {
key: val
};
})();
I do not know the format of your translate.js files, but you could also consider putting the translations in a json file, if it's a fixed output for each language. Which I think would be the safest solution.
I managed to load the locale files dynamically like this :
Note that my locale string formatting might not be ideal, and ignore the polyfill if you don't plan on supporting old browsers.
import {addLocaleData} from 'react-intl';
const locale = // get this from browser language
// ensure that the polyfill is loaded before calling this
const isUsingIntlPolyfill = Object.prototype.hasOwnProperty.call(window, 'IntlPolyfill');
// eg: turns 'fr-fr' into 'fr-FR' because intl polyfill locale files are formatted like this
const formatLocale = str => `${str.split('-')[0]}${str.split('-')[1] ? `-${str.split('-')[1].toUpperCase()}` : ''}`;
if (isUsingIntlPolyfill) {
const polyfill = document.createElement('script');
// path of the file might differ for your setup
polyfill.setAttribute('src', `/i18n/polyfill/${formatLocale(locale)}.js`);
document.getElementsByTagName('head')[0].appendChild(polyfill);
}
const script = document.createElement('script');
// path of the file might differ for your setup
script.setAttribute('src', `/i18n/${locale.split('-')[0]}.js`);
script.onload = () => {
addLocaleData([...window.ReactIntlLocaleData[locale.substring(0, 2)]]);
// your locale is loaded, do some more stuff from here ...
};
document.getElementsByTagName('head')[0].appendChild(script);

Resources