I wanted to change ID of textarea using onclick button. So I created two buttons across my field. Each on click run a function.
Issue: It just replace my id first time and second time when i click on second button it throws error saying "Uncaught TypeError: Cannot set property 'id' of null at ti_pos_fun (index.html:491)"
HTML code-
<div>
<label for="usr">ti:</label> <i class="glyphicon glyphicon-check" onclick="ti_pos_fun()"></i> <i class='glyphicon glyphicon-unchecked' onclick="ti_neg_fun()"></i>
</div>
I am trying to use two buttons- example
Now when you click check button- ti runs the onclick function "ti_pos_fun".
Function are as follows
function ti_neg_fun ()
{
var a = document.getElementById("jsel");
a.id = "ti_neg";
//$("#ti_neg").text('angry');
document.getElementById('ti_neg').innerHTML = 'angry';
}
function ti_pos_fun ()
{
var a = document.getElementById("jsel");
a.id = "ti_pos";
document.getElementById('ti_pos').innerHTML = 'hahahahaha';
//$("#ti_pos").text('hahahaha');
}
Textarea code where these ids are going & their text.
<div class="col-md-10">
<H3> textarea</H3>
<textarea id = "jsel"></textarea>
</div>
You click on button 1 - check button
It gets id and text in textarea
When you click on button 2- uncheck button
It fails
Its not working on 2nd click because you are overwriting the id of that element
//a.id = "ti_neg";
so on 2nd click there is no element with id jsel and below statement will return null and it will not work.
document.getElementById("jsel");
function ti_neg_fun ()
{
var a = document.getElementById("jsel");
//a.id = "ti_neg";
//$("#ti_neg").text('angry');
document.getElementById('jsel').innerHTML = 'angry';
}
function ti_pos_fun ()
{
var a = document.getElementById("jsel");
//a.id = "ti_pos";
document.getElementById('jsel').innerHTML = 'hahahahaha';
//$("#ti_pos").text('hahahaha');
}
<div>
<label for="usr">ti:</label> <i class="glyphicon glyphicon-check" onclick="ti_pos_fun()">1</i> <i class='glyphicon glyphicon-unchecked' onclick="ti_neg_fun()">2</i>
</div>
<div class="col-md-10">
<H3> textarea</H3>
<textarea id = "jsel"></textarea>
</div>
That's because the ID isn't jsel anymore you need something like this, if it can't find jsel check for the ID the other function set and visa versa. EDIT: added snip that works.
function ti_pos_fun ()
{
var a = document.getElementById("jsel");
if (a != null){
a.id = "ti_pos";
document.getElementById('ti_pos').innerHTML = 'hahahahaha';
//$("#ti_pos").text('hahahaha');
}else{
var a = document.getElementById("ti_neg");
a.id = "ti_pos";
document.getElementById('ti_pos').innerHTML = 'hahahahaha';
//$("#ti_pos").text('hahahaha');
}
}
function ti_neg_fun ()
{
var a = document.getElementById("jsel");
if(a != null){
a.id = "ti_neg";
//$("#ti_neg").text('angry');
document.getElementById('ti_neg').innerHTML = 'angry';
}else{
var a = document.getElementById("ti_pos");
a.id = "ti_neg";
//$("#ti_neg").text('angry');
document.getElementById('ti_neg').innerHTML = 'angry';
}
}
<div>
<label for="usr">ti:</label> <i class="glyphicon glyphicon-check" onclick="ti_pos_fun()">postitive</i> <i class='glyphicon glyphicon-unchecked' onclick="ti_neg_fun()">negative</i>
</div>
<div class="col-md-10">
<H3> textarea</H3>
<textarea id = "jsel"></textarea>
</div>
Related
I created the sort button HTML element in javascript, and the button shows in the console, however, when I apply the sortList.style.display = "block"; to make it display when the add button is clicked the sort button shows as well, not sure why it is not showing.
I do have the sort button hidden in the CSS file, only so that I can have it show when submit event is clicked
const elements = {
form: document.querySelector("#new-task-form"),
input: document.querySelector("#new-task-input"),
list: document.querySelector("#tasks"),
cal: document.querySelector("#calendar"),
sort: document.querySelector(".sort")
elements.list.addEventListener('click',event => {
const {target} = event;
const {id} = target.dataset;
const task = id ? document.querySelector('[data-id="${id}"]'): null;
const sortList = event.target.querySelector(".sort")
for (var i=0; i < sortList.length; i++){
sortList[i].style.display = 'block';
}
}
There is more to the code, however, it's just the sortList.style.display = "block"; I need help with.
Let me know if you need more of the code if the above does not help?
I believe you want sortList to be done as follows:
const sortList = event.target.getElementsByClassName('sort')
for (var i=0; i < sortList .length; i++) {
sortList[i].style.display = 'block';
}
I solved the issue. The issue was that it was not needed to add a display:none in the CSS file because the sort button would appear anyway along with the task list.
as its only created in the tasks.innerHTML.
const tasks = document.createElement("div");
tasks.innerHTML = `
<button class = "sort" >Sort</button>
<div class="task" date-id = "${id}">
<div class="content">
<input type ="checkbox" class="tick">
<input type ="text" class = text id = "text" readonly>${task}
<label class = "due-date" for ="text">${date}</label>
<input type ="date" class = date id = "date">
</div>
<div class = "actions">
<button class="edit" data-id="${id}">Edit</button>
<button class="delete" data-id="${id}">Delete</button>
</div>
</div>
`
I have some To Do-s that are dinamically created by the user:
<div>
<h3 class = 'taskTitle'>do homework </h3>
<p class = 'taskDate'>Expires: 2021.12.31</p>
<input type = button class = 'delBtn' value = 'x'></input>
<input type = button class = 'expandBtn' value = '...'></input>
</div>
<div>
<h3 class = 'taskTitle'>workout </h3>
<p class = 'taskDate'>Expires: 2021.10.11</p>
<input type = button class = 'delBtn' value = 'x'></input>
<input type = button class = 'expandBtn' value = '...'></input>
</div>
**etc.**
On click of the expandBtn a pop up window appears that would contain the title (h3) and the date (p) of the specific To Do.
script:
function showDescription(){
const expandBtns= document.querySelectorAll('.expandBtn')
expandBtns.forEach(btn => {
btn.addEventListener('click', function(event){
let popUp = document.createElement('div')
popUp.classList.add('descriptionBox')
let title = event.target.parentNode.firstChild.textContent **<--says its undefined**
let date = event.target.parentNode.firstChild.textContent **<--says its undefined**
popUp.innerHTML = `
<h3>${title}</h3>
<p class = 'description'> lorem ipsum </p>
<p class = 'dateDescription'>${date}</p>
<input class = 'delDescription' type = button value = 'x'></input>`
const todos = document.querySelector('#todos')
todos.appendChild(popUp)
//close button for popUp
const delDescription = document.querySelectorAll('.delDescription')
delDescription.forEach(btn => {
btn.addEventListener('click', function (event){
event.target.parentNode.remove()
})
})
// alert(document.querySelector('.activeProject').textContent)
})
})
}
So how could I target them? querySelector isn't good either, as I have more than 1 To Do-s. Any help appreciated!
You could add a unique id or class to all the div elements. For example:
<div id="to-do-1"><p>Test</p></div>
<button onclick="myFunction()">Click Me!</button>
<script>
function myFunction() {
document.getElementById("to-do-1").style.display = "inline";
}
</script>
<style>
#to-do-1 {
display: none;
}
</style>
Select all expandBtn
var btn = document.getElementsByClassName("expandBtn")
Create a loop and addEventListener for all of them
for(let i =0; i < btn.length; i++) {
btn[i].addEventListener("click", function () {
let h3 = this.parentNode.getElementsByTagName("h3")[0];
let p = this.parentNode.getElementsByTagName("p")[0];
alert("h3 = "+ h3.innerText + " & p = " + p.innerText);
}
}
now when the user clicking on anyone of them it's will search for h3, p who is belong to the parent of this button
Using .children will get you what you want:
document.addEventListener("click",ev=>{
if (ev.target.className!=="expandBtn") return;
const [name,date]=[...ev.target.parentNode.children].slice(0,2).map(e=>e.textContent)
console.log(name,date);
// further code for popup ...
})
<div>
<h3 class = 'taskTitle'>do homework </h3>
<p class = 'taskDate'>Expires: 2021.12.31</p>
<input type = button class = 'delBtn' value = 'x'></input>
<input type = button class = 'expandBtn' value = '...'></input>
</div>
<div>
<h3 class = 'taskTitle'>workout </h3>
<p class = 'taskDate'>Expires: 2021.10.11</p>
<input type = button class = 'delBtn' value = 'x'></input>
<input type = button class = 'expandBtn' value = '...'></input>
</div>
.firstChild will return the first childNode, which in your case would have been a blank and a line-break and not the <h3> element you expected.
.children on the other hand will return a collection of all child elements (like: <div>, <p>, <span>, ... etc.), the chained .slice(0,2) will slice off the first two elements only.
I am trying to create a 'favourites' system where the user can click on a star in the top right of a button to add that course to their list of 'favourites'. Here is the HTML for said button (there are 6 of them and all 6 are the same):
<button class="divflexbuttonitem">
<div class="libraryfaviconcontainer">
<i class="libraryfavicon" onclick="toggleFavourite()"></i>
</div>
</button>
And here is my (attempt at) JavaScript for the toggleFavourite() function:
function toggleFavourite() {
console.log("Running toggleFavourite();");
var favicon = document.getElementsByClassName("libraryfavicon");
var faviconCount = favicon.length;
var favArray = new Array();
var favArrayString = favArray.toString();
var i;
for(i = 0; i < faviconCount; i++) {
favArray.push(favicon[i].id);
}
alert(favArray.length);
alert(favArrayString);
let favourite = false;
if (favicon[i].style.backgroundImage == 'url("libraryfavselected.png")') {
favourite = true;
}
else if (favicon[i].style.backgroundImage == 'url("libraryfavunselected.png")') {
favourite = false;
}
if (!favourite) {
favicon[i].style.backgroundImage = 'url("libraryfavselected.png")';
console.log("Added to Favourites");
}
else {
favicon[i].style.backgroundImage = 'url("libraryfavunselected.png")';
console.log("Removed from Favourites");
}
}
I am trying to get all elements with a specific class name, add them to an array, and call them from an array to change the url of the 'favicon' of the specific favicon that was pressed. However, my code does not work whatsoever and i am lost as to how to correctly code it.
There are better ways to structure this type of application, but here is some really simple code to get you started.
You can see that the fav class is toggled on and off when an item is clicked, and then we can get all the current favourites by querying all elements with the fav class.
const toggleFavourite = (event) => {
if (event.target){
const clickTarget = event.target;
clickTarget.classList.toggle('fav')
}
}
//Example use, get all favs and attach the text as a new element
const getFavs = () => {
const favs = document.querySelectorAll('.fav');
const favContainer = document.querySelector('.favs')
favContainer.innerHTML = "";
for( let fav of favs){
let newFav = document.createElement('div');
newFav.textContent = fav.textContent;
favContainer.appendChild(newFav)
}
}
.fav {
color: red;
}
<i class="" onclick="toggleFavourite(event)">1</i>
<i class="" onclick="toggleFavourite(event)">2</i>
<i class="" onclick="toggleFavourite(event)">3</i>
<i class="" onclick="toggleFavourite(event)">4</i>
<i class="" onclick="toggleFavourite(event)">5</i>
<button id="getFavs" onclick="getFavs()">Get Favs</button>
<section class='favs'>
</section>
I'm trying to use javascript to create a set of elements over and over again once the user enters a text where it would display the text with a button with an image in it to the side of it but I could not find a way to do it efficiently.
The current method I was going to create would require each element to have a id tag to it so that I could call appendChild to join the elements together.
I also need to have a create element be appended into another create element which adds to the issues
This is what I'm trying to achieve in the html code (the div would not be needed to be created as it is in the html code already)
function addToList(input) {
console.log(x);
let task = document.createElement('p');
task.id = x;
task.appendChild(document.createTextNode(input));
document.getElementById('listOfTasks').appendChild(task);
addCheckBox(x);
x++;
}
function addCheckBox(id) {
let checkBox = document.createElement('a');
checkBox.className = 'button is-rounded is-small';
checkBox.id = 'checkBox';
document.getElementById(id).appendChild(checkBox);
let a = document.createElement('span');
a.className = 'icon is-small';
a.id = 'apple';
document.getElementById(id).appendChild(a);
let b = document.createElement('i');
b.className = 'fas fa-check';
document.getElementById(id).appendChild(b);
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css"/>
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<div class="container">
<div id="listOfTasks"></div>
</div>
<section class="section">
<div class="container">
<div class="field box form-popup" id="addTask">
<div class="control">
<div class="field is-grouped">
<label class="label"><b>Task to add</b></label>
</div>
<input
type="text"
class="input"
placeholder="Enter Task"
id="task"
required
/>
</div>
<button
type="button submit"
class="button is-success"
id="submit"
onclick="closeForm()"
>
Add
</button>
</div>
</div>
</section>
The current output is shown as
Would be grateful if anyone knows a better method to do this
Make a function that reduces boilerplate code when creating element
function create(name, props, children) {
let elem = document.createElement(name); // create it
const parent = props.parent // we use parent prop elsewhere
let keys = Object.keys(props) // collect keys
keys = keys.filter(function(key) { // remove parent prop from keys
return key !== 'parent'
})
keys.forEach(function(key) { // assign props to element
elem.setAttribute(key, props[key])
})
if (children && children.length) { // add children to element
children.forEach(function(child) {
elem.appendChild(child)
})
}
if (parent) { // attach to parent
document.getElementById(id).appendChild(elem);
}
return elem // return it, to customize further
}
And then
function addCheckBox(id) {
create('a', {
id: 'checkBox', // simple prop
parent: id, // parent prop
class: 'button is-rounded is-small' // simple prop
})
var span = create('span', {
parent: id,
id: 'apple',
class: 'icon is-small'
}, [create('i', { // demo of children
class: 'fa fa-check'
}])
span.setAttribute('data-something', 1) // demo of customizing
}
I have form which gets clone when user click on add more button .
This is how my html looks:
<div class="col-xs-12 duplicateable-content">
<div class="item-block">
<button class="btn btn-danger btn-float btn-remove">
<i class="ti-close"></i>
</button>
<input type="file" id="drop" class="dropify" data-default-file="https://cdn.example.com/front2/assets/img/logo-default.png" name="sch_logo">
</div>
<button class="btn btn-primary btn-duplicator">Add experience</button>
...
</div>
This my jquery part :
$(function(){
$(".btn-duplicator").on("click", function(a) {
a.preventDefault();
var b = $(this).parent().siblings(".duplicateable-content"),
c = $("<div>").append(b.clone(true, true)).html();
$(c).insertBefore(b);
var d = b.prev(".duplicateable-content");
d.fadeIn(600).removeClass("duplicateable-content")
})
});
Now I want every time user clicks on add more button the id and class of the input type file should be changed into an unique, some may be thinking why I'm doing this, it I because dropify plugin doesn't work after being cloned, but when I gave it unique id and class it started working, here is what I've tried :
function randomString(len, an){
an = an&&an.toLowerCase();
var str="", i=0, min=an=="a"?10:0, max=an=="n"?10:62;
for(;i++<len;){
var r = Math.random()*(max-min)+min <<0;
str += String.fromCharCode(r+=r>9?r<36?55:61:48);
}
return str;
} var ptr = randomString(10, "a");
var className = $('#drop').attr('class');
var cd = $("#drop").removeClass(className).addClass(ptr);
Now after this here is how I initiate the plugin $('.' + ptr).dropify().
But because id is still same I'm not able to produce clone more than one.
How can I change the id and class everytime user click on it? is there a better way?
Working Fiddle.
Problem :
You're cloning a div that contain already initialized dropify input and that what create the conflict when you're trying to clone it and reinitilize it after clone for the second time.
Solution: Create a model div for the dropify div you want to clone without adding dropify class to prevent $('.dropify').dropify() from initialize the input then add class dropify during the clone.
Model div code :
<div class='hidden'>
<div class="col-xs-12 duplicateable-content model">
<div class="item-block">
<button class="btn btn-danger btn-float btn-remove">
X
</button>
<input type="file" data-default-file="http://www.misterbilingue.com/assets/uploads/fileserver/Company%20Register/game_logo_default_fix.png" name="sch_logo">
</div>
<button class="btn btn-primary btn-duplicator">Add experience</button>
</div>
</div>
JS code :
$('.dropify').dropify();
$("body").on("click",".btn-duplicator", clone_model);
$("body").on("click",".btn-remove", remove);
//Functions
function clone_model() {
var b = $(this).parent(".duplicateable-content"),
c = $(".model").clone(true, true);
c.removeClass('model');
c.find('input').addClass('dropify');
$(b).before(c);
$('.dropify').dropify();
}
function remove() {
$(this).closest('.duplicateable-content').remove();
}
Hope this helps.
Try this:
$(function() {
$(document).on("click", ".btn-duplicator", function(a) {
a.preventDefault();
var b = $(this).parent(".duplicateable-content"),
c = b.clone(true, true);
c.find(".dropify").removeClass('dropify').addClass('cropify')
.attr('id', b.find('[type="file"]')[0].id + $(".btn-duplicator").index(this)) //<here
$(c).insertBefore(b);
var d = b.prev(".duplicateable-content");
d.fadeIn(600).removeClass("duplicateable-content")
})
});
Fiddle
This does what you specified with an example different from yours:
<div id="template"><span>...</span></div>
<script>
function appendrow () {
html = $('#template').html();
var $last = $('.copy').last();
var lastId;
if($last.length > 0) {
lastId = parseInt($('.copy').last().prop('id').substr(3));
} else {
lastId = -1;
}
$copy = $(html);
$copy.prop('id', 'row' + (lastId + 1));
$copy.addClass('copy');
if(lastId < 0)
$copy.insertAfter('#template');
else
$copy.insertAfter("#row" + lastId);
}
appendrow();
appendrow();
appendrow();
</script>
Try adding one class to all dropify inputs (e.g. 'dropify'). Then you can set each elements ID to a genereted value using this:
inputToAdd.attr('id', 'dropify-input-' + $('.dropify').length );
Each time you add another button, $('.dropify').length will increase by 1 so you and up having a unique ID for every button.