I'm trying to create a program that reads data from a database and lists it on a page. Everything works well only now I have a problem deleting data.
The data from the database will be listed and a delete button will be added to them. Each button has the same id as data. When I press the button, the function with the id parameter should be started using onclick.
But I get this error:
index.html:1 Uncaught ReferenceError: reply_click is not defined
at HTMLButtonElement.onclick (index.html:1:1)
My code:
<script type="module">
window.onload = products;
const issuesRef = ref(db, 'student');
var id = 0;
function products() {
onValue(issuesRef, (snapshot) => {
snapshot.forEach(snap => {
const issue = snap.val();
var id_2 = document.createElement("div");
var div = document.createElement("div");
var div2 = document.createElement("div");
var div3 = document.createElement("div");
var div4 = document.createElement("div");
var buttn = document.createElement("button");
buttn.setAttribute("id", issue.RollNo);
buttn.setAttribute("onclick", "reply_click(this.id)");
function reply_click(clicked_id){
console.log(clicked_id);
}
id_2.innerHTML = ++id;
div.innerHTML = issue.NameOfStd;
div2.innerHTML = issue.Gender;
div3.innerHTML = issue.RollNo;
div4.innerHTML = issue.Section;
buttn.innerHTML = "delete";
document.body.appendChild(id_2)
document.body.appendChild(div);
document.body.appendChild(div2);
document.body.appendChild(div3);
document.body.appendChild(div4);
document.body.appendChild(buttn);
})
});
}
</script>
I think the problem is in the function reply_click() and in buttn.setAttribute...
First of all, functions by default work like local variables, defining a function in the scope of another function makes it a local function, this is not a good practice but it can be done.
Now about the reason for the error, onclick is looking for a global function that doesn't exist, in fact the recommended thing is to use addEventListener.
I should also say that using var is not recommended, please read:
https://phoenix35.js.org/good-practices.html
const buttn = document.createElement("button");
buttn.id = issue.RollNo
buttn.addEventListener("click", function(event) {
// all events pass the Event object as first parameter to the callback
// Event objects has a target property pointing to the HTMLElement who fired the event
// HTMLElement has attributes as properties so you can get the id by event.target.id
console.log(event.target.id);
});
/*
works too but not recommended:
buttn.onclick = function(event) {
console.log(event.target.id);
}
*/
References:
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
https://developer.mozilla.org/en-US/docs/Web/API/Event
https://developer.mozilla.org/en-US/docs/Web/API/Event/target
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
First of all the id attribute doesn't take the value as numbers so you need to put like id=btn-1
Function reply_click is declared below buttn.setAttribute, since JavaScript reads the code procedurally, this function does not yet exist in the scope. Additionally, since the function is the same for each button (the ID is only a parameter), there's no need to declare this inside the forEach at all.
Try putting the reply_click function in the global scope, above the products() function.
function reply_click(clicked_id) {
console.log(clicked_id)
}
function products() {
...
Move the reply_click from the scope of products function to global scope since onClick is looking for function in global scope.
<script>
window.onload = onLoadListener;
function onClickListener(id) {
console.log(id);
}
function onLoadListener() {
var buttn = document.createElement("button");
buttn.innerHTML = "CLICK";
buttn.setAttribute("id", '123');
buttn.setAttribute("onclick", "onClickListener(this.id)");
document.getElementById("app").append(buttn);
}
</script>
Related
I am working on a small project where by i need to create objects with form field data. In short i have a constructor function that retrieves values from each form field like this:
var Task = function() {
this.title = document.getElementById("task-title").value;
this.date = document.getElementById("task-date").value;
this.option = document.getElementById("task-option").value;
}
What i need is create a NEW instance of object each time somebody clicks the submit button. What i have so far is this:
var submitBtn = document.getElementById('#someID');
submitBtn.addEventListener('click', function(event) {
event.preventDefault();
var newTask = new Task();
});
This works in that it create an object, but the objects gets overridden each time the button is pressed. I need a new instance of the object to be created each time the buttoned is pressed.
Is this possible ? if not is there a more viable alternative to constructor functions? Thank you so much.
You're defining that newTask variable inside the enventlistener and then immediately assigning the new Task to it. Your code is doing everything you told it to do. Namely, create a new variable and assign a new instance of task to it. After the function ends the newTask is destroyed because there's nothing to do anymore and nowhere else in your code are you able to reach it.
Why dont you try this:
var submitBtn = document.getElementById('#someID');
var myTasks = [];
submitBtn.addEventListener('click', function(event) {
event.preventDefault();
myTasks.push(new Task());
});
That's because you are always putting the value in the same var, you will need make a array with your objects, so you don't lose your old object
var submitBtn = document.getElementById('#someID');
var newTask = [];
submitBtn.addEventListener('click', function(event) {
event.preventDefault();
newTask.push(new Task());
});
I am trying to come up with a page on which, when user clicks a file button on the page, I try to execute the JS on the page. And I am trying to use OOP / class so hopefully it can be reused later. Here is my test code:
// This is the "class".
function BearUpload() {
// some values will go here...
}
// Add a few functions
BearUpload.prototype.function1 = function () {
console.log("function1 called");
}
BearUpload.prototype.handleFileSelect = function (evt) {
console.log("handleFileSelect called");
this.function1();
}
var myBear = new BearUpload(); // Create a global variable for the test
$(document).ready(function () {
var some_condition_goes_here = true;
if (some_condition_goes_here) {
$("#my-file-select-button").change(myBear.handleFileSelect);
}
});
However, it gets error like:
TypeError: this.function1 is not a function
this.function1();
Any idea about this?
Thanks!
Bind myBear to your change eventListener
In general when you access this from handleFileSelect, this refers to the html element.
i.e. this = <input type="file" id="my-file-select-button">
$("#my-file-select-button").change(myBear.handleFileSelect.bind(myBear));
The bind() method creates a new function that, when called, has its
this keyword set to the provided value, with a given sequence of
arguments preceding any provided when the new function is called.
MDN doc
You are trying to call function1 on DOM object but you have to call on jQuery object
$(this).function1();
That's because when bound as a handler to jQuery events, this would refer to the element on which the event is triggered.
I would rather change your code like this
// Create only one global variable for your app
var APP = {};
// Create class using immediate function/closure
APP.BearUpload = (function(){
//declare private variables here
// Constructor
var bearUpload = function() {
// some values will go here...
}
// Add a few functions
bearUpload.prototype.function1 = function () {
console.log("function1 called");
}
bearUpload.prototype.handleFileSelect = function (evt) {
console.log("handleFileSelect called");
this.function1();
}
return bearUpload;
}());
APP.myBear = new APP.BearUpload();
$(document).ready(function () {
var some_condition_goes_here = true;
if (some_condition_goes_here) {
$("#my-file-select-button").change(function(e){
// do something with event 'e'
APP.myBear.handleFileSelect.call(APP.myBear, e);
});
}
});
do not use "this", it is confusing some time.
BearUpload.prototype ={
function1:function(){
var self = this;
...
},
handleFileSelect:function(e){
var self = this;
...
}
}
I'm new to JQuery so if this is a obvious question my apologies. I have a simple form which holds some input fields. On the change-event I want to change a pre-defined array. The change event is triggered, but in this change-event I want to loop through all input-element again to fill/change an array. However the iteration doesn't work.
<script>
jsonObj = [];
$(document).ready(function(){
$("input[class=domain]").change(function(){
refreshData();
});
$("input[class=domain]").each(function() {
var domain = $(this).attr("name");
var score = $(this).val();
item = {}
item ["domain"] = domain;
item ["score"] = score;
jsonObj.push(item);
});
});
function refreshData() {
alert("Text Changed"); <<-- This line is reached.
$(document)("input [class=domain]").each(function() {
//TO DO: Refresh jsonObj
alert(domain); /<<-- This line is not reached.
});
}
</script>
A second question would be if it is possible to shorten this code. Now I have two separate function in the document.ready-event Change and
each both on the input-element.
T.I.A.
$('.domain').each(function(){
alert(domain);
})
use this instead of $(document)("input [class=domain]").each
You are missing a . and probably a .find before .each. Below code is what it should look like:
$(document).find("input[class=domain]").each(function() {
//TO DO: Refresh jsonObj
alert(domain);
});
UPDATE
With respect to your second question I would have shortened the code as below if the lines inside your .each was same as it would be in refreshData function:
jsonObj = [];
$(document).ready(function(){
refreshData();//call once on DOM Load
$('.domain').change(refreshData); //attach it as named function to change event
});
function refreshData() {
//keep all this code here
$(".domain").each(function() {
var domain = $(this).attr("name");
var score = $(this).val();
item = {}
item["domain"] = domain;
item["score"] = score;
jsonObj.push(item);
});
}
I have done some rectification and you can shorten it like:
<script>
jsonObj = []; // array declaration
$(document).ready(function(){
$("input.domain").change(function(){ // <----better to use a class selector
refreshData($("input.domain")); // <----pass the object in the function
}).change(); //<----trigger it on load to execute
});
function refreshData(el) { // get the passed object in the func arg
$(el).each(function() { // <----have a loop on it this way
var domain = $(this).attr("name"); // extract the name on current object in collection
var score = this.value; // get the value of the current object in iteration
var item = {}; // declare a new object
item["domain"] = domain; // set new prop and assign value here
item["score"] = score; // set new prop and assign value here
jsonObj.push(item); // now push the object in the array.
});
}
</script>
This expression is wrong for some reasons:
$(document)("input [class=domain]")
A. There must be no space between input and [class=domain]. This is the difference between "input that has the class domain" (input[class=domain]) and "input that one of its sub-nodes has the class domain" (input [class=domain]).
B. In order to query inside a jQuery element you need to use the find method like this: $(document).find("input [class=domain]"). But because document is the root element, you can just write $("input [class=domain]").
P.S
In CSS-selectors (like jQuery) there is a special syntax for searching classes, so instead you can just write input.domain.
So this how the line should look at last:
$("input.domain").each...
You can read more about css selectors here.
Strange code...
$(document)("input [class=domain]").each
Try this:
$("input[class=domain]").each
How can I pass an attribute of div into it's own onclick function?
For example, I have this div:
var join_button = document.createElement("div");
join_button.setAttribute("class", "join_button");
join_button.innerHTML = "join";
join_button.setAttribute("room_name", name);
join_button.setAttribute("onclick", "join_room()");
Now, in function join_room() I need to know the room name attribute of this join_button. Ofcourse, I have not only one join_button on my page, I dont know it's names and I need to handle all of them.
If I try to use this It tells me undefined is not a function
function join_room() {
this.getAttribute("room_name");
}
undefined is not a function
You can use this to read the objects attribute.
var join_room = function() {
var room_name = this.getAttribute('room_name);
}
then set the onclick like this.
join_button.onclick = join_room;
JSFIDDLE
I have this function:
function createElement() {
var element1 = document.createElement("div");
element1.id = "el1";
//...
}
the problem is that when I create another function, let say editElement(), I cannot access element1 from within the new function as it's out of scope.
I could declare element1 outside of those functions, but then the problem is that element1 gets declared all the time. But I may need to create the element only in the fraction of the cases, only when a user presses a button and creadeElement() gets called. I want to save system resources and call document.createElement("div") only when I really need it, but I also need to access it from within multiple functions. Is there a way to do it?
you can simply assign your new element to window so it available in global scope
function createElement() {
window.element1 = document.createElement("div"); //Meke new element global.
element1.id = "el1";
}
function useElement() {
//now you can use element1 directly. as it is inside the global scope.
}
Instead, do something like this:
var element1 = null;
function createElement() {
element1 = document.createElement("div");
element1.id = "el1";
//...
}
function useElement() {
if(!element1)createElement()
//...
}
This will make the element available outside the createElement function, but won't create the element until it's needed.
You can use an object:
var elementHandler = {
createElement: function() {
this.element1 = document.createElement("div");
this.element1.id = "el1";
// ...
},
editElement: function() {
// Use this.element1 here...
}
};
You call createElement and editElement like this:
elementHandler.createElement();
elementHandler.editElement();
(Or you might just call them create and edit as there's no need to repeat the word "element" all over the place...)
If hooking them up to an event, be sure you call them such that elementHandler is this within the call:
// Using an anonymous function
someElement.addEventListener("click", function() {
elementHandler.createElement();
}, false);
// Or using ES5's `bind`
someElement.addEventListener("click", elementHandler.createElement.bind(elementHandler), false);
// *NOT* like this:
someElement.addEventListener("click", elementHandler.createElement, false);