How to add an image from a template form with JS? - javascript

i'm studying JS and at the moment i'm not really good with it. I created a page (a kind of social network) and i need to add an image from an URL when i fill a form. The form has 2 fields: Image title and URL
the initial cards that i have on the page, i handle to insert them from an array. But i can't understand how to add a single photo from a form.
The new photo should appear as first image, the previous 1st image should be at the 2nd place and so on, cards can be deleted when i click on a button but i didn't really got how to do it, and the like buttons should work for every single cards... i've was looking for it on google and i found some stuffs but they didn't work for me.
how can i solve it?
my code:
HTML
<section class="cards" id="cards">
<!-- images will be added here-->
<div class="cards__add-form-overlay">
<form class="cards__add-form">
<button class="cards__add-form-close-icon"></button>
<p class="cards__add-form-text">New place</p>
<input type="text" placeholder="Name" class="cards__add-form-first-field" id="ImageName" value= "">
<input type="text" placeholder="Image URL" class="cards__add-form-second-field" id="URL" value= "">
<button type="submit" class="cards__add-form-submit">create</button>
</form>
</div>
</section>
<template class="elements" id="elements">
<div class="element">
<div class="element__card">
<img class="element__photo" src="" alt="">
<div class="element__button-container">
<button type="button" class="element__trash-button" id="trashbutton">
</div>
<div class="element__text">
<p class="element__place"></p>
<button type="button" class="element__like-button" id="likebutton" onclick="toggle()"></button>
</div>
</div>
</template>
<script type="text/javascript" src="./script.js"></script>
</body>
</html>
JS
// IMAGES //
// description: adding photos in the page from an array with JS //
const initialCards = [
{ name:'', link:''},
{ name:'', link:''},
{ name:'', link:''},
{ name:'', link:''},
{ name:'', link:''},
{ name:'', link:''}
];
initialCards.forEach(card => cardItem(card));
function cardItem(cardData) {
const container = document.getElementById("cards");
const cardTemplate = document.getElementById("elements").content;
const newCard = cardTemplate.cloneNode(true);
const elementImage = newCard.querySelector('.element__photo');
const elementText = newCard.querySelector('.element__place');
elementImage.src = cardData.link;
elementText.textContent = cardData.name;
container.append(newCard);
}
----- Until here all good
// description: adding popup when clicking on + button, and close with X button //
document.querySelector('.profile__add-button').addEventListener('click', function () {
document.querySelector('.cards__add-form-overlay').style.visibility = 'visible';
});
document.querySelector('.cards__add-form-close-icon').addEventListener('click', function () {
document.querySelector('.cards__add-form-overlay').style.visibility = 'hidden';
});
document.querySelector('.cards__add-form-submit').addEventListener('click', function () {
document.querySelector('.cards__add-form-overlay').style.visibility = 'hidden';
});
document.querySelector('.profile__add-button').addEventListener('click', function () {
document.querySelector('.cards__add-form').style.visibility = 'visible';
});
document.querySelector('.cards__add-form-close-icon').addEventListener('click', function () {
document.querySelector('.cards__add-form').style.visibility = 'hidden';
});
document.querySelector('.cards__add-form-submit').addEventListener('click', function () {
document.querySelector('.cards__add-form').style.visibility = 'hidden';
});
// description: adding photo through popup with 2 fields, name and URL //
const addPhoto = document.querySelector('.cards__add-form');
const imageNameInput = document.querySelector('.cards__add-form-first-field');
const imageUrlInput = document.querySelector('.cards__add-form-first-field');
function handleAddCardFormSubmit(evt) {
evt.preventDefault();
const element = createCard(imageNameInput.value, imageUrlInput.value);
elements.prepend(element);
imageNameInput.value = '';
imageUrlInput.value = '';
closePopup(evt.target.closest('.cards__add-form'));
}
function createCard(name, link) {
const elementTemplate = document.querySelector('#element-template').content;
const element = elementTemplate.querySelector('.element').cloneNode(true);
const elementImage = element.querySelector('.element__photo');
const elementTitle = element.querySelector('.element__place');
elementImage.src = link;
elementTitle.textContent = name;
//like button//
const likeButton = element.querySelector('.element__like-button');
likeButton.addEventListener('click', () => likeButton.classList.toggle('element__like-button_active'));
//delete cards //
element.addEventListener('click', function (evt) {
if (evt.target.classList.contains('element__trash-button')) {
evt.currentTarget.remove();
}
if (evt.target.classList.contains('element__photo')) {
openImagePopup(name, link);
}
});
return element;
}
initialCards.forEach(({name, link}) => elements.append(createCard(name, link)));
with this code, the new image doesn't appear, about like button console says that toogle() is not defined, and delete button don't delete the image but no error in the console

Related

Cannot link JavaScript in index.html.erb to Python Script (Button not working)

I'm trying to upload an image on a Ruby on Rails view using a button that on-click should send an argument to a python script. However I am facing issues.
Here is the code in my index.html.erb:
<div class="container">
<div class="wrapper">
<div class="image">
<img src="" onerror="this.style.display='none'" id = 'image_file'/>
</div>
<div class="content">
<div class="icon">
<i class="fas fa-cloud-upload-alt"></i>
</div>
<div class="text" style="text-align:center;">
No Image
</div>
</div>
<div id="cancel-btn">
<i class="fas fa-times"></i>
</div>
<div class="file-name">
File name here
</div>
</div>
<button onclick="defaultBtnActive()" id="custom-btn" class="active-btn" name="default-btn">Choose a file</button>
<input id="default-btn" type="file" name ='file' hidden>
<button id="submit-btn" class="active-btn modal-btn">Submit</button>
</div>
<div class="bg-modal">
<div id="error">
<div class="close">+</div>
<h1>Error</h1>
<p>Error occurred with uploading image. Did you upload the right file type?</p>
</div>
</div>
</div>
<script>
const wrapper = document.querySelector(".wrapper");
const fileName = document.querySelector(".file-name");
const defaultBtn = document.querySelector("#default-btn");
const customBtn = document.querySelector("#custom-btn");
const cancelBtn = document.querySelector("#cancel-btn i");
const img = document.querySelector("img");
const submitBtn = document.querySelector("#submit-btn");
let regExp = /[0-9a-zA-Z\^\&\'\#\{\}\[\]\,\$\=\!\-\#\(\)\.\%\+\~\_ ]+$/;
function defaultBtnActive(){
defaultBtn.click();
}
defaultBtn.addEventListener("change", function(){
var file = this.files[0];
if(isFileImage(file)){
const reader = new FileReader();
reader.onload = function(){
const result = reader.result;
img.src = result;
img.style.display = 'inline';
const placeholder = document.querySelector(".content");
placeholder.style.visibility = "hidden";
wrapper.classList.add("active");
}
cancelBtn.addEventListener("click", function(){
img.src = "";
wrapper.classList.remove("active");
location.reload();
})
reader.readAsDataURL(file);
}
else {
modalBg.classList.add('bg-active');
}
if(this.value){
let valueStore = this.value.match(regExp);
fileName.textContent = valueStore;
}
});
var modalBtn = document.querySelector('.modal-btn');
var modalBg = document.querySelector('.bg-modal');
var modalClose = document.querySelector('.close');
let {PythonShell} = require('python-shell');
var cloudurl = 'gs://uscentralbucket-vcm/testus.csv';
let options = {
mode: 'text',
pythonOptions: ['-u'], // get print results in real-time
scriptPath: '../auto-ml/',
args: [cloudurl]
};
modalBtn.addEventListener('click', function() {
var file = defaultBtn.files[0];
if (isFileImage(file)) {
window.location.href = "<%= main_review_path %>";
python_script.stdout.on('data', (data) =>{
console.log('Data received from python script', data.toString())
});
PythonShell.run('consolidated_steps.py', options, function (err, results) {
if (err) throw err;
// results is an array consisting of messages collected during execution
console.log('results: %j', results);
});
}
else {
modalBg.classList.add('bg-active');
}
});
modalClose.addEventListener('click', function() {
modalBg.classList.remove('bg-active');
})
function isFileImage(file) {
const acceptedImageTypes = ['image/gif', 'image/jpeg', 'image/png'];
return file && acceptedImageTypes.includes(file['type'])
}
</script>
After applying the relevant PythonShell code, the button in my Rails view does not work anymore. It works if I comment out let{PythonShell} = require('python-shell').
Is there a way to fix the button to be functional again and run the function in the javascript code (and link to my python script), or is there another way to link Javascript within a .erb file to Python?

How to make edit function that replaces existing text for To-Do App?

I created an editItem function which creates the HTML element when the user clicks on the edit button, I am not sure how to go about when the user inputs, when the update replaces the existing task.
I am aware that the replace can be used to replace the new-task-created class in the renderList
Just a note I created a new object updateEl which contains the class of the modal and I also created updateTask function which returns the new values been inserted.
My thinking pattern is this: If I need to create new values for the user input, time, and date, that new information can just replace the old information when they click save (UpdateTask function)
HTML
<div class="form">
<input class ="user-input" type="text">
<input class="date" type="date">
<input class="time" type="time">
<button onclick="addTask()" class="add" id="add">+</button>
</div>
<div class="list"></div>
<div class="modal"></div>
JS
//local storage key
const STORAGE_KEY = "tasks-storage-key";
// variables object
const el = {
form: document.querySelector(".form"),
input: document.querySelector(".user-input"),
list: document.querySelector(".list"),
date: document.querySelector(".date"),
time: document.querySelector(".time"),
};
const updateEl = {
formUpdate: document.querySelector(".form-update"),
inputUpdate: document.querySelector(".user-input"),
modal: document.querySelector(".modal"),
dateUpdate: document.querySelector(".date-update"),
timeUpdate: document.querySelector(".time-update"),
};
//Create ID
const createId = () =>
`${Math.floor(Math.random() * 10000)}${new Date().getTime()}`;
//variable of empty array that gets new task
let taskList = JSON.parse(window.localStorage.getItem(STORAGE_KEY) ?? "[]");
renderList();
function makeNewTask() {
const data = {
id: createId(),
taskNew: el.input.value,
taskDate: el.date.value,
taskTime: el.time.value,
};
return data;
}
function updateTask() {
const dataUpdate = {
id: createId(),
inputUpdate: updateEl.inputUpdate.value,
dateUpdate: updateEl.dateUpdate.value,
timeUpdate: updateEl.timeUpdate.value,
};
return dataUpdate;
}
function renderList() {
// This resets the list innerHTML to the new list
el.list.innerHTML = taskList.map(function (data) {
return `<div class="task">
<div class="task-content">
<div class="task" data-id="${data.id}">
<div class="new-task-created">${data.taskNew}</div>
<label class="due-date">${data.taskDate}</label>
<label class="due-time">${data.taskTime}</label>
</div>
<div class="action-buttons">
<button onclick="editItem(event)" class="edit" data-id="${data.id}">Edit</button>
<button onclick="deleteItem(event)" class="delete" data-id="${data.id}">Delete</button>
<button onclick="completeItem(event)" class="complete" data-id="${data.id}">Complete</button>
</div>
</div>`;
});
}
//event listner that listens for add button.
function addTask() {
taskList.push(makeNewTask());
// store the list on localstorage because data changed
storeList();
// render list again because you've added a new entry
renderList();
}
//function that removes task from array with delete button.
function deleteItem(event) {
taskList.splice(taskList.indexOf(event.target.dataset.id), 1);
// store the list on localstorage because data changed
storeList();
// render list again because entry was removed
renderList();
}
//function that stores task list.
function storeList() {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(taskList));
}
//function that that edits tasks with date and time.
function editItem() {
let updateInput = document.createElement("div")
updateInput.innerHTML = `<div class="form-update">
<input class ="input-update" type="text">
<input class="date-update" type="date">
<input class="time-update" type="time">
<button onclick="UpdateTask()" class="update" id="update">Save</button>
<button onclick="close()" class="close" id="close">Save</button>
</div>`;
updateEl.modal.appendChild(updateInput);
}
function UpdateTask(){
}
//function that that completes task.
function completeItem(event) {
const element = event.target.closest(".task-content");
let taskItem = element.querySelector(".new-task-created");
let dateItem = element.querySelector(".due-date");
let timeItem = element.querySelector(".due-time");
// style..
taskItem.style.textDecoration = "line-through";
dateItem.style.textDecoration = "line-through";
timeItem.style.textDecoration = "line-through";
}
I got it to update doing it this way.
function editItem(event) {
const editEl = event.target.closest(".task");
let taskUpdate = editEl.querySelector(".new-task-created");
let dateUpdate = editEl.querySelector(".due-date");
let timeUpdate = editEl.querySelector(".due-time");
let editbtn = editEl.querySelector(".edit");
if (editbtn.innerHTML.toLowerCase() == "edit"){
taskUpdate.removeAttribute("readonly");
dateUpdate.removeAttribute("readonly");
timeUpdate.removeAttribute("readonly");
taskUpdate.focus();
editbtn.innerHTML = "Save";
}
else{
taskUpdate.setAttribute("readonly", "readonly");
dateUpdate.setAttribute("readonly", "readonly");
timeUpdate.setAttribute("readonly", "readonly");
editbtn.innerHTML = "Edit";
}

li element vanish after page reload

I am trying to add a li element in the below div (Functionality is to upload an attachment)
See below pic 1
My JavaScript functionality of Submit button adds the Li in the div perfectly fine. But, when I refresh the page it's gone.
<input type="file" id="real-file" hidden="hidden" />
<button type="button" id="custom-button">CHOOSE A FILE</button>
<span id="custom-text">No file chosen, yet.</span>
<button type="button" id="submit-button" onclick="Submit()">Submit</button>
<div id="collapseThree">
</div>
<script>
const realFileBtn = document.getElementById("real-file");
const customBtn = document.getElementById("custom-button");
const customTxt = document.getElementById("custom-text");
const submitBtn = document.getElementById("submit-button");
const slides = [];
var str = '';
customBtn.addEventListener("click", function() {
realFileBtn.click();
});
window.addEventListener('load', (event) => {
console.log(slides)
console.log('The page has fully loaded yo');
// document.getElementById("collapseThree").innerHTML
});
/* window.onload = document.getElementById("slideContainer").innerHTML
*/
function Submit() {
console.log("going in");
document.getElementById("collapseThree").innerHTML += str
}
realFileBtn.addEventListener("change", function() {
if (realFileBtn.value) {
customTxt.innerHTML = realFileBtn.value.match(
/[\/\\]([\w\d\s\.\-\(\)]+)$/
)[1];
console.log(customTxt.innerHTML)
slides.push(customTxt.innerHTML);
slides.forEach(function(slide) {
str = '<li>' + slide + '</li>';
});
console.log(arr)
console.log(slides)
} else {
customTxt.innerHTML = "No file chosen, yet.";
}
});
</script>
You can use localStorage to save and read data. Simply call
function getSlides() {
var slidesJson = localStorage.getItem('slides') || '[]';
return JSON.parse(slidesJson);
}
to get all current slides and
function setSlides(slides) {
localStorage.setItem('slides', JSON.stringify(slides))
}
to save the current state of the array.

Is it possible to keep cursor in the text area after a click even?

I'm a front-end learner. I created a primitive app that I saw in Duolingo or Memrise. It consists of a text-area and buttons situated below with extra Spanish letters which can be used in necessary. I'm a Spanish learner and need to use the letters to type outside the language apps.
The problem is that when I type in the text and click on the button with a specific extra letter the cursor in the text area disappears. I need to click again in the text area. It's a bit annoying. In Duolingo it stays in the area and the use of mouse is reduced. Does anyone know how to fix it?
<div class="container">
<div class="input-container">
<div class="upper-box">
<textarea name="" id="textarea" rows="3"></textarea>
</div>
<div class="input-keyboard">
<button id="a">á</button>
<button id="e">é</button>
<button id="i">í</button>
<button id="o">ó</button>
<button id="u">ú</button>
<button id="n">ñ</button>
<button id="exclamation">¡</button>
<button id="question">¿</button>
<button id="clear">Clear</button>
<!-- input-keyboard ends below -->
</div>
</div>
</div>
const textarea = document.querySelector("#textarea");
// buttons
const clearBtn = document.querySelector("#clear");
const aBtn = document.querySelector("#a");
const eBtn = document.querySelector("#e");
const iBtn = document.querySelector("#i");
const oBtn = document.querySelector("#o");
const uBtn = document.querySelector("#u");
const nBtn = document.querySelector("#n");
const exlBtn = document.querySelector("#exclamation");
const queBtn = document.querySelector("#question");
aBtn.addEventListener("click", function () {
let inputText = (textarea.value += "á");
});
eBtn.addEventListener("click", function () {
let inputText = (textarea.value += "é");
});
iBtn.addEventListener("click", function () {
let inputText = (textarea.value += "í");
});
oBtn.addEventListener("click", function () {
let inputText = (textarea.value += "ó");
});
uBtn.addEventListener("click", function () {
let inputText = (textarea.value += "ú");
});
nBtn.addEventListener("click", function () {
let inputText = (textarea.value += "ñ");
});
exlBtn.addEventListener("click", function () {
let inputText = (textarea.value += "¡");
});
queBtn.addEventListener("click", function () {
let inputText = (textarea.value += "¿");
});
clearBtn.addEventListener("click", function () {
let inputText = (textarea.value = "");
});
In each button click event, you can set focus the textarea after inserting the respective letter. Check below example (With jQuery):
$(document).on("click", "#a", function () {
var text = $("#textarea").val();
$("#textarea").val(text + 'á');
$("#textarea").focus();
}
Even with Javascript you can have a similar approach.
document.getElementById("textarea").focus();

How to delete a DOM element from an array after you've clicked on it?

I was making a simple to-do list. You submit itens from an input and they go to the To-DO section. When you click over them they go to the 'Done' section. And when you click on them again, they vanish forever. It was all working fine.
But I realized the doneItens array kept growing in length, which I wanted to optimize. So I came up with this line of code
doneItens.splice(i, 1);
which goes inside an onclick event, which you can see in the code inside the deleteDone function.
That gives the error, though,
Error:{
"message": "Uncaught TypeError: doneItens.splice is not a function"
If I put it outside and below the onclick event it also doesn't work. How can I do it?
var input = document.getElementById('play');
var toDo = document.getElementsByTagName('ol')[0];
var done = document.getElementById('done');
function handleSubmit(event) {
event.preventDefault();
const newItem = document.createElement('li');
newItem.setAttribute('class', 'item');
newItem.append(input.value);
toDo.append(newItem);
input.value='';
deleteItem();
}
function deleteItem() {
const toBeDone = document.getElementsByClassName('item');
for(let i = 0; i < toBeDone.length; i++) {
toBeDone[i].onclick = () => {
appendItemDone(toBeDone[i]);
toBeDone[i].style.display = 'none';
deleteDone();
}
}
}
function appendItemDone(item) {
const newDone = document.createElement('li');
newDone.setAttribute('class', 'feito')
newDone.append(item.innerText);
done.append(newDone);
}
function deleteDone() {
const doneItens = document.getElementsByClassName('feito');
console.log('done length', doneItens.length)
for (let i = 0; i < doneItens.length; i++) {
doneItens[i].onclick = () => {
doneItens[i].style.display = 'none';
doneItens.splice(i, 1);
}
}
}
<div id='flex'>
<form class='form' onsubmit='handleSubmit(event)'>
<input placeholder='New item' type='text' id='play'>
<button>Send</button>
</form>
<div id='left'>
<h1 id='todo' >To-do:</h1>
<p class='instruction'><i>(Click over to mark as done)</i></p>
<ol id='here'></ol>
</div>
<div id='right'>
<h1>Done:</h1>
<p class='instruction'><i>(Click over to delete it)</i></p>
<p id='placeholder'></p>
<ol id='done'></ol>
</div>
</div>
With the use of JavaScript DOM API such as Node.removeChild(), Element.remove() and Node.parentNode, your task can be solved with this code:
const input = document.getElementById('play');
const todo = document.getElementById('todo');
const done = document.getElementById('done');
function handleSubmit(event) {
event.preventDefault();
// create new "todo" item
const newTodo = document.createElement('li');
newTodo.textContent = input.value;
todo.append(newTodo);
// clean the input field
input.value = '';
// listen to "click" event on the created item to move it to "done" section
newTodo.addEventListener('click', moveToDone);
}
function moveToDone(event) {
// remove "click"-listener to prevent event listener leaks
event.target.removeEventListener('click', moveToDone);
// move clicked todo-element to "done" section
const newDone = event.target.parentNode.removeChild(event.target);
done.append(newDone);
// listen to "click" event on the moved item to then completely delete it
newDone.addEventListener('click', removeFromDone);
debugElementsLeak();
}
function removeFromDone(event) {
// remove "click"-listener to prevent event listener leaks
event.target.removeEventListener('click', removeFromDone);
// complete remove clicked element from the DOM
event.target.remove();
debugElementsLeak();
}
function debugElementsLeak() {
const todoCount = todo.childElementCount;
const doneCount = done.childElementCount;
console.log({ todoCount, doneCount });
}
<div id="flex">
<form class="form" onsubmit="handleSubmit(event)">
<input placeholder="New item" type="text" id="play">
<button>Add item</button>
</form>
<div id="left">
<h1>To-do:</h1>
<p class="instruction"><em>(Click over to mark as done)</em></p>
<ol id="todo"></ol>
</div>
<div id="right">
<h1>Done:</h1>
<p class="instruction"><em>(Click over to delete it)</em></p>
<p id="placeholder"></p>
<ol id="done"></ol>
</div>
</div>
You'll want to use splice,
and then rather than use hidden, 'refresh' the done element by adding all elements in the spliced array.
I've commented my code where I've made changes and why
var input = document.getElementById('play');
var toDo = document.getElementsByTagName('ol')[0];
var done = document.getElementById('done');
function handleSubmit(event) {
event.preventDefault();
const newItem = document.createElement('li');
newItem.setAttribute('class', 'item');
newItem.append(input.value);
toDo.append(newItem);
input.value='';
deleteItem();
}
function deleteItem() {
const toBeDone = document.getElementsByClassName('item');
for(let i = 0; i < toBeDone.length; i++) {
toBeDone[i].onclick = () => {
appendItemDone(toBeDone[i].cloneNode(true));
toBeDone[i].style.display = 'none';
deleteDone();
}
}
}
function appendItemDone(item) {
const newDone = document.createElement('li');
newDone.setAttribute('class', 'feito')
newDone.append(item.innerText);
done.append(newDone);
}
function deleteDone() {
var doneItens = document.getElementsByClassName('feito');
for (let i = 0; i < doneItens.length; i++) {
doneItens[i].onclick = () => {
var splicedArray = spliceFromArray(doneItens,doneItens[i]);// NEW BIT -CALL NEW SPLICE FUNCTION
done.innerHTML=""; // NEW BIT - SET OVERALL DONE TO BLANK ON DELETE
for(var index in splicedArray){// NEW BIT - fOR EACH RETURNED ELEMENT IN THE SPLICE, ADD IT TO THE OVERALL DONE ELEMENT
done.appendChild(splicedArray[index]);
}
}
}
}
function spliceFromArray(arrayInput,element){// NEW BIT - SPLICE FUNCTION THAT RETURNS SPLICED ARRAY
var array = Array.from(arrayInput);
var index = array.indexOf(element);
if(index!=-1){
if(array.length==1 && index == 0){
array = [];
}
else{
array.splice(index,1);
}
}
return array;
}
<div id='flex'>
<form class='form' onsubmit='handleSubmit(event)'>
<input placeholder='New item' type='text' id='play'>
<button>Send</button>
</form>
<div id='left'>
<h1 id='todo' >To-do:</h1>
<p class='instruction'><i>(Click over to mark as done)</i></p>
<ol id='here'></ol>
</div>
<div id='right'>
<h1>Done:</h1>
<p class='instruction'><i>(Click over to delete it)</i></p>
<p id='placeholder'></p>
<ol id='done'></ol>
</div>
</div>

Categories

Resources