Store image from gallery and display - javascript

I have coded a small API gallery that fetches an image from an API, but I need to know how do I store and save an image?
My codepen: https://codepen.io/aaron_1986/pen/VwdvqWB
Below is my JavaScript code that I used to create the API gallery that fetches an image from an API and displays the image on screen.
function get_image() {
let access_key = 'YmMDTJCtZaK6veBdER5WkjyqmgGBRyH6Bpdqt7WcrM4';
let url = `https://api.unsplash.com/photos/random /?client_id=YmMDTJCtZaK6veBdER5WkjyqmgGBRyH6Bpdqt7WcrM4`;
let imageElement = document.querySelector('.image');
fetch(url)
.then(function(response){
//console.log(response.json())
return response.json();
})
.then(function(jsonData){
imageElement.src = jsonData.urls.regular;
})
}
//// Array
let selected_images = [];
document.querySelectorAll('.large-image').forEach(function(img, idx) {
img.src = "" + idx;
img.addEventListener('click', function({target: src}){
if(!selected_images.includes(src)) {
selected_images.push(src);
}
console.log(selected_images);
});
});

Below is a basic example on how to save an email and image using sessionStorage similar to the example provided by OP.
NOTE
OP mentioned they have to recreate the example site they provided (indicating some sort of assignment), however this example is not a full solution to that. This is only to answer the specific question asked by OP "how do I store and save an image?".
const _SaveData = () => {
// Get elements
let img = document.querySelector('.image'),
email = document.querySelector('#email').value;
// Validate email address format
if(!/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
console.log(`Invalid Email Address!`)
return
}
// Set the new data and retrive any previously stored data
let newData = {
email: email,
img: img.src
},
data = (sessionStorage.getItem("data")) ? JSON.parse(sessionStorage.getItem("data")) : []
// Update data
data = [...data, newData]
// Save data
sessionStorage.setItem("data", JSON.stringify(data))
console.log(`Data Saved!`)
}
As long as you add a field with the id email and set your Save Data! button's onclick value to _SaveData(), this will do the intended purpose. As far as recreating that site goes, there are additional things you will need to do (such as validating duplicate images/emails and generating new images upon save).

Related

Table contents disappear on refresh

I'm trying to make a money tracker but every time I refresh they disappear. Anyone know how I can use local storage to make them stay? I've tried using local storage but I can't wrap my head around it and it is very confusing for me. Code Pen - https://codepen.io/jordandevelops/pen/wvPWzxL
const table = document.getElementById('contentTable'),
inputText = document.getElementById('inputText'),
inputPrice = document.getElementById('inputPrice'),
inputDate = document.getElementById('inputDate'),
form = document.getElementById('form');
form.addEventListener('submit', (e) => {
e.preventDefault();
addNewItem();
});
function addNewItem(){
if(inputPrice.value == ''){
alert('Error, please enter price of purchase.');
return;
}
if(inputDate.value == ''){
alert('Error, please enter date of purchase.');
return;
}
let newTr = document.createElement('tr');
let newTd1 = document.createElement('td');
let newTd2 = document.createElement('td');
let newTd3 = document.createElement('td');
table.appendChild(newTr);
newTr.appendChild(newTd1);
newTr.appendChild(newTd2);
newTr.appendChild(newTd3);
newTr.classList.add('createdTr')
newTd1.classList.add('tdName');
newTd2.classList.add('tdPrice');
newTd3.classList.add('tdDate');
newTd1.innerText = inputText.value;
newTd2.innerText = `$${inputPrice.value}`;
newTd3.innerText = inputDate.value;
}
In local storage, you store the data structure in JSON format (not the HTML that contains the data).
To store data:
function addNewItem(){
//... check and validate the input like you do
// grab the current local storage or create an empty container
let theData = localStorage.get('theData') || "[]";
theData = JSON.parse(theData); // get it into object format
//add to it
theData.push({text: inputText.value, price: inputPrice.value, date: inputDate.value});
// store that back into local storage as a string
localStorage.set('theData', JSON.stringify(theData));
//... continue on with your code
To retrieve the data, do it on page load
document.addEventListener('DOMContentLoaded', () => {
let theData = localStorage.get('theData') || "[]";
JSON.parse(theData).forEach(d => {
// ... this is where you take the existing local storage list and populate it into your HTML.
// You can leverage your existing addNewItem function but you'll need to update it to allow for sending input directly into it.
})
Local storage can work ok, but I'd recommend using IndexedDB if you want to store data like this.
IndexedDB is even more complicated than local storage in some ways, but there's a great library called "Dexie" that makes it a lot easier. You can see it here: https://dexie.org/
Using Dexie, you can save, restore and query your data. It will take a little time to experiment with and learn how to do, but it will be a great tool to have in your toolbox.

How to connect loop data to pdfgeneratorapi with wix corvid?

I'm generating PDF by using https://pdfgeneratorapi.com/.
Now I can show data one by one using this code.Can any one give me suggestion how can show all data with loop or any other way?
This below photos showing my template from pdfgenerator .
This is the code I'm using to generate PDF
let communicationWay1=[
{0:"dim"},
{1:"kal"}
];
let cstomerExpence1=[
{0:"dim"},
{1:"kal"}
];
let title="test";
let names="test";
let phone="test";
let email="test";
let maritalStatus="test";
let city="test";
let other="test";
const result = await wixData.query(collection)
.eq('main_user_email', $w('#mainE').text)
.find()
.then( (results) => {
if (results.totalCount>0) {
count=1;
// title=results.items[1].title;
names=results.items[0].names;
email=results.items[0].emial;
phone=results.items[0].phone;
maritalStatus=results.items[0].maritalStatus;
city=results.items[0].city;
other=results.items[0].cousterExpenses_other;
title=results.items[0].title;
communicationWay=results.items[0].communicationWay;
cstomerExpence=results.items[0].cstomerExpence;
}
if (results.totalCount>1) {
names1=results.items[1].names;
email1=results.items[1].emial;
phone1=results.items[1].phone;
maritalStatus1=results.items[1].maritalStatus;
city1=results.items[1].city;
other1=results.items[1].cousterExpenses_other;
title1=results.items[1].title;
communicationWay1=results.items[1].communicationWay;
cstomerExpence1=results.items[1].cstomerExpence;
}
} )
.catch( (err) => {
console.log(err);
} );
// Add your code for this event here:
const pdfUrl = await getPdfUrl
({title,names,email,phone,city,maritalStatus,other,communicationWay,cstomerExpence,title1,
names1,email1,phone1,city1,maritalStatus1,other1,communicationWay1,cstomerExpence1
});
if (count===0) { $w("#text21").show();}
else{ $w("#downloadButton").link=wixLocation.to(pdfUrl);}
BELOW CODE IS BACKEND CODE/JSW CODE.
Also I want to open pdf in new tab. I know "_blank" method can be used to open a new tab.But I'm not sure how to add it with the url
import PDFGeneratorAPI from 'pdf-generator-api'
const apiKey = 'MYKEY';
const apiSecret = 'MYAPISECRET';
const baseUrl = 'https://us1.pdfgeneratorapi.com/api/v3/';
const workspace = "HELLO#gmail.com";
const templateID = "MYTEMPLATEID";
let Client = new PDFGeneratorAPI(apiKey, apiSecret)
Client.setBaseUrl(baseUrl)
Client.setWorkspace(workspace)
export async function getPdfUrl(data) {
const {response} = await Client.output(templateID, data, undefined, undefined, {output: 'url'})
return response
}
Just put it in a while loop with a boolean condition.
You can create a variable, for example allShowed, and set its value to False. After that, create another variable, for example numberOfDataToShow, and set it as the number of elements you want to display. Then create a counter, countShowed, initialized with 0 as its value.
Now create a while loop: while allShowed value is False, you loop (and add data).
Everytime a piece of your data is showed, you increment the value of countShowed (and set it to go on adding/showing data). When countShowed will have the exact same value of numberOfDataToShow, set allShowed to True. The loop will interrupt and all your data will be showed.
You would need to use the Container or Table component in PDF Generator API to iterate over a list of items. As #JustCallMeA said you need to send an array of items. PDF Generator API now has an official Wix Velo (previously Corvid) tutorial with a demo page: https://support.pdfgeneratorapi.com/en/article/how-to-integrate-with-wix-velo-13s8135

How do I only render the updated stat - websockets

right now the entire div re-renders, but I am searching for a way to only re-render the updated statistic
these are parts of what I have now
updatestats.js
document.querySelector("#submit").addEventListener("click", function (e) {
let country = document.querySelector("#country").value
let numberCases = document.querySelector("#number").value
fetch(base_url + "/api/v1/stats/updatestats", {
method: "put",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
"country": country,
"numberCases": numberCases
})
}).catch(err => {
console.log(err);
})
primus.write({ "action": "update" })
stats.js
primus.on("data", (json) => {
if (json.action === "update") {
document.querySelector("#overview").innerHTML = ""
appendInfo()
}
})
function appendInfo() {
fetch(base_url + "/api/v1/stats", {
method: "get",
headers: {
'Content-Type': 'application/json'
},
}).then(response => {
return response.json();
}).then(json => {
json.data.stats.forEach(stat => {
let country = stat.country
let numberCases = stat.numberCases
let p = document.createElement('p')
let text = document.createTextNode(`${country}: ${numberCases}`)
p.appendChild(text)
let overview = document.querySelector("#overview")
overview.appendChild(p)
})
}).catch(err => {
console.log(err);
})
}
window.onload = appendInfo();
stats.pug
body
h1 Cases by country
div#overview
So if I only update the country Belgium I only want that statistic to be changed. Now everything seems to reload
What I meant with my suggestion is to keep te communication of data between client and server strictly in the sockets. Meaning when one user updates 1 value on their end, that value will be send to the server and stored. After the server finished storing the value, that same value will be sent to all other clients. This way you only send and receive the parts that have been changed without having to download everything on every change.
I might not be able to write the code exactly as it should be as I have limited experience with Primus.js and know little about your backend.
But I would think that your frontend part would look something like this. In the example below I've removed the fetch function from the click event. Instead send the changed data to the server which should handle those expensive tasks.
const countryElement = document.querySelector("#country");
const numberCasesElement = document.querySelector("#number");
const submitButton = document.querySelector("#submit");
submitButton.addEventListener("click", function (e) {
let data = {
action: 'update',
country: countryElement.value,
numberCases: numberCasesElement.value
};
primus.write(data);
});
Now the server should get a message that one of the clients has updated some of the data. And should do something with that data, like storing it and letting the other clients know that this piece of data has been updated.
primus.on('data', data => {
const { action } = data;
if (action === 'update') {
// Function that saves the data that the socket received.
// saveData(data) for example.
// Send changed data to all clients.
primus.write(data);
}
});
The server should now have stored the changes and broadcasted the change to all other clients. Now you yourself and other will receive the data that has been changed and can now render it. So back to the frontend. We do the same trick as on the server by listening for the data event and check the action in the data object to figure out what to do.
You'll need a way to figure out how to target the elements which you want to change, you could do this by having id attributes on your elements that correspond with the data. So for example you want to change the 'Belgium' paragraph then it would come in handy if there is a way to recognize it. I won't go into that too much but just create something simple which might do the trick.
In the HTML example below I've given the paragraph an id. This id is the same as the country value that you want to update. This is a unique identifier to find the element that you want to update. Or even create if it is not there.
The JavaScript example after that receives the data from the server through the sockets and checks the action. This is the same data that we send to the server, but only now when everybody received we do something with it.
I've written a function that will update the data in your HTML. It will check for an element with the id that matches the country and updates the textContent property accordingly. This is almost the same as using document.createTextNode but with less steps.
<div id="overview">
<p id="Belgium">Belgium: 120</p>
</div>
const overview = document.querySelector("#overview");
primus.on('data', data => {
const { action } = data;
if (action === 'update') {
updateInfo(data);
}
});
function updateInfo(data) {
const { country, numberCases } = data;
// Select existing element with country data.
const countryElement = overview.querySelector(`#${country}`);
// Check if the element is already there, if not, then create it.
// Otherwise update the values.
if (countryElement === null) {
const paragraph = document.createElement('p');
paragraph.id = country;
paragraph.textContent = `${country}: ${numberCases}`;
overview.append(paragraph);
} else {
countryElement.textContent = `${country}: ${numberCases}`;
}
}
I hope that this is what you are looking for and / or is helpful for what you are trying to create. I want to say again that this is an example of how it could work and has not been tested on my end.
If you have any questions or I have been unclear, then please don't hesitate to ask.
To elaborate #EmielZuurbier's suggestion in the comment, please try the following code.
//Client-side
primus.emit('data',data);
primus.on("dataUpdated", (json) => {
});
//Server-side
primus.on('data',data =>{
//process it here and then
//send it out again
primus.emit('dataUpdated','the data you want to send to the front end');
})

React JS Local Storage update on view change

How can I update certain properties of a local storage item or object as new data is inputted throughout the user journey and not lose what was previously entered or if the user decides to update?
My journey of 5 containers consisting of asking the user to input the following:
Name: string
Avatar: integer
Favourite Genres: multiple strings
On the first view I have created the local storage object / item that sets the name within the handleSubmit function.
handleSubmit(event) {
event.preventDefault();
//Profile object
let profile = { 'name': this.state.name, 'avatar': null, 'genres': '' };
// Put the object into storage
localStorage.setItem('profile', JSON.stringify(profile));
// Retrieve the object from storage
var retrievedObject = localStorage.getItem('profile');
//Log object
console.log('retrievedObject: ', JSON.parse(retrievedObject));
//On form submission update view
this.props.history.push('/profile/hello');
}
On my second view I want to update only the avatar property and maintain what the user had inputted in the previous view.
I'm doing this within the handleSelect function like so:
handleSelect(i) {
let selectedAvatarId;
let avatars = this.state.avatars;
avatars = avatars.map((val, index) => {
val.isActive = index === i ? true : false;
return val;
});
this.setState({
selectedAvatarId: selectedAvatarId
})
//Profile object
let profile = { 'avatar': i };
//Update local storage with selected avatar
localStorage.setItem('profile', JSON.stringify(profile));
}
You will need to read the existing value from localStorage, parse it as JSON and then manipulate the data, and write it back. There are numerous libraries out there for easily working with localStorage, but something along the lines of this should work as a generic function:
function updateProfile = (updatedData) => {
const profile = JSON.parse(localStorage.getItem('profile'));
Object.keys(updatedData).forEach((key) => {
profile[key] = updatedData[key];
});
localStorage.setItem('profile', JSON.stringify(profile));
}
If you use object spread, it could look a lot cleaner too:
function updateProfile = (updatedData) => {
const profile = {
...JSON.parse(localStorage.getItem('profile')),
...updatedData
};
localStorage.setItem('profile', JSON.stringify(profile));
}
There should probably be some safety checks in the above code, but hopefully gives you an idea for a starting point.
The only option as far as I know is to get it as a Json, amend accordingly and then save it is again.

Write an uploads metadata with information stored data in Firebase DB

I've been hitting my head against the wall on this for about 2 hours and I think I've just lost sight of the problem a bit.
I have an incremental field saved as "index" that upon a file upload starting has it's value increase by 1.
I am able to query the database and pull the value for index to the console and receive the updated value.
I can't for the life of me work out how to insert the value I've created and subsequently logged to the console (definitely doesn't need to be logged just did this to prove to myself I wasn't going insane) into the uploads metadata at the next stage of the script. I have tried everything I can think of - I've watched about an hour of youtube videos, and I can safely say beyond a shadow of a doubt I could turn my app into a running counter of peoples file uploads but I can't add it to their upload metadata!
Help me stack overflow you're my only hope!
Code below hopefully outlines the issue - the query is going into the variable indexRef but the actual info I need is in the nested variable "key" which is just the data snapshot value. This seems like it should be so easy.
var indexRef = firebase.database().ref('index');
indexRef.once('value')
.then(function(snapshot){
var key = snapshot.val()
console.log(key)
})
var imagekey = firebase.database().ref('images/').push().key;
var downloadURL = uploadTask.snapshot.downloadURL;
var updates = {};
var postData = {
url: downloadURL,
score: 1500,
index: indexRef,
user: user.uid
};
updates ['/images/'+imagekey] = postData;
firebase.database().ref().update(updates);
Thanks in advance and I apologise if the answer to this is trivial and I've wasted someones time!
Remember the then method returns promises https://firebase.googleblog.com/2016/01/keeping-our-promises-and-callbacks_76.html
var indexRef = firebase.database().ref('index');
// Declare variables outside of block to access within
var imagekey = firebase.database().ref('images/').push().key;
var downloadURL = uploadTask.snapshot.downloadURL;
var updates = {};
indexRef.once('value')
.then(function(snapshot){
var key = snapshot.val()
// Return key variable for use
return key;
})
.then(function(key){
// You can now access the key variable in here
var postData = {
url: downloadURL,
score: 1500,
index: key,
user: user.uid
};
updates ['/images/'+imagekey] = postData;
firebase.database().ref().update(updates);
})
Hope this helps you

Categories