Input addEventListener on change not firing - javascript

I have a single input to upload a image.
html
<main>
<input id="hs-p" type="file" accept="image/*" capture="camera">
</main>
<script type="text/javascript">
let hsp = new HPS();
</script>
I want to listen for when this input changes ( when someones adds an image to it).
js
let imageInput = null;
class HSP {
constructor() {
this.imageInput = document.getElementById('hs-p');
if (this.imageInput) {
this.imageInput.addEventListener("change", this.uploadImage());
}
}
uploadImage() {
console.log("upload image", this.imageInput);
}
}
module.exports = HSP;
When someone adds an image it should call the uploadImage callaback. However this function is only firing once when the page loads and never fires when i add a image to the input or change the input image.
I am using node & webpack to output the above custom library/sdk which i then import into my html.

Change your event to this:
this.imageInput.addEventListener("change", () => this.uploadImage());
Or to this:
this.imageInput.addEventListener("change", this.uploadImage.bind(this));
What you are doing is calling uploadImage and passing the result of that to the listener. You want to pass the reference to the listener.

change this.imageInput.addEventListener("change", this.uploadImage()); to this.imageInput.addEventListener("change", this.uploadImage); ( removed the () after this.uploadImage ).

Related

Livewire property is null when value updated through php

I have a very simple livewire component
class Test extends Component
{
public $test = "test";
public function submit()
{
dd($this->test);
}
public function render()
{
return view('livewire.test');
}
}
and view
<div>
<form wire:submit.prevent="submit" method="post">
<input type="text" wire:model="test" id="test">
<button type="button" id="ok">ok</button>
<button type="submit">submit</button>
</form>
<script>
const button = document.getElementById('ok');
button.addEventListener('click', function() {
const input = document.getElementById('test');
input.value = "Test";
});
</script>
</div>
I simplified the code for illustrative purposes to show that JavaScript changes a value.
When I click ok what changes the value from test to Test and then submit, I get test shown instead of Test.
I except to see Test. What am I doing wrong?
It seems that the Livewire Component is not recognising the change from the Javascript code, as the following function doesn't fire either:
public function updatedTest()
{
dd("Fired");
}
What #Peppermingtology said isn't entirely true. He is right that it is not the preferred way of handling Livewire, but sometimes you can't escape it.
You can indeed use AlpineJS and that will solve your issue, but you can also cast a normal change event. Your Livewire variable isn't updating because Livewire has not detected any change. That's because programattically updated inputs don't trigger any event by default to prevent infinite event loops.
If you simply add an event, it should also work:
const input = document.getElementById('test');
input.value = "Test";
let event = new Event('change', {bubbles: true});
input.dispatchEvent(event);
You can't manipulate properties in that manner with Livewire. The preferred way is to use the AlpineJS entangle method which specifically caters for sharing state between Livewire and your client.
That being said, you can achieve what you're after without using AlpineJS. Replacing your existing JavaScript with the below should get you the result you're after.
<script>
document.addEventListener('livewire:load', (evt) => {
const button = document.getElementById('ok');
button.addEventListener('click', function() {
document.getElementById('test').value = #this.test = 'Test';
});
})
</script>

How to prevent onmouseout function to get called when onclick has been called already?

I'm trying to create a Like button with an input with the type image which its src changes when it is hovered/clicked. I want to change it when it is hovered and have its previous source back when it is unhoverd. So I used onmouseover and onmouseout to do this. I also used onclick to the src when it is clicked on.
The problem is that when I click on it, it changes as intended but as soon as I move the mouse so it is not hovered anymore, It calls the onmouseout function and this is not what I need.
Edit: There are multiple buttons so I cant't use a boolean variables to check if was clicked.
What should I do to not execute onmouseout when it was clicked on?
<input type="image" src="path" onmouseover="likeHover(this)" onmouseout="likeUnhover(this)" onclick="like(this, '{{post.id}}')">
function likeHover(btn) {
btn.src = '../../static/network/img/heart-pink.png';
}
function likeUnhover(btn) {
btn.src = '../../static/network/img/heart-black.png';
}
function like(btn) {
btn.src = '../../static/network/img/heart-red-filled.png';
}
You could use a boolean variable, and set it to true if the button was clicked.
And use addEventListener in the JS code and not the HTML attributes:
const input = document.querySelector("input[type=image]");
let clicked = false;
input.addEventListener("mouseover", (e) => {
if (!clicked)
e.target.src = '../../static/network/img/heart-pink.png';
});
input.addEventListener("mouseout", (e) => {
if (!clicked)
e.target.src = '../../static/network/img/heart-black.png';
});
input.addEventListener("click", (e) => {
clicked = true;
e.target.src = '../../static/network/img/heart-red-filled.png';
});
<input type="image" src="path">

Is it possible to have acces to innerHTML 'id' from otger part of the code?

I have following code, where, based on event, I add some html code. I would like to refer to 'id' from this dynamically injected html in other event (or just from other part of the code):
<div id="choice"></div>
var decisionList = document.getElementById("decisionList");
decisionList.addEventListener("change", function () {
var finalChoice = document.getElementById("choice");
finalChoice.innerHTML='<input id="finalDate" type="date">'
}
and other event referring to 'id' from innerHTML:
var payment = document.getElementById("finalDate");
payment.addEventListener("change", function () {
var textDate = payment.textContent;
alert(textDate);
})
The above is not working. Is it possible or not?
It is possible, but make that payment getter lazy. What that means is, instead of setting up that second change listener right away (in your other code), make that other code a function. Then in your first trigger, where you created the extra div or input or something, call that setup function.
decisionList.addEventListener("change", function () {
const finalChoice = document.getElementById("choice");
finalChoice.innerHTML='<input id="finalDate" type="date">'
createFinalDateListener();
}
function createFinalDateListener() {
const payment = document.getElementById("finalDate");
payment.addEventListener("change", function () {
const textDate = payment.textContent;
alert(textDate);
});
}
Here's a similar example. I do not have the input immediately. Or listener. And I only create a listener after I create the input.
// Here's the main trigger
function addExtraElements() {
// let's create a datepicker dynamically.
document.querySelector('#placeholder').innerHTML = '<input type="date" placeholder="pick date">';
listenDateChanges();
// TODO: don't forget to add cleanup code! Each time you fill that innerHTML, the old listener will remain
}
// Here's your datepicker listener
function listenDateChanges() {
const datePickerEl = document.querySelector('input[type="date"]');
if (!datePickerEl) {
console.log('no picker');
return;
}
datePickerEl.addEventListener('change', () => alert(datePickerEl.value));
}
<div id="placeholder">
Placeholder
</div>
<button onclick="addExtraElements()">Add extra elements</button>

Changing what function to call depending on which button is pressed

Okay So I what to have 3 buttons
<div id="button1" onclick="choose1()">Button1</div>
<div id="button2" onclick="choose2()">Button2</div>
<div id="button3" onclick="choose3()">Button3</div>
And a start button
<div id="startButton" onclick="noFunction()">Start</div>
I want to make it so that pressing on of the 3 option buttons it changes what function will be called from the start button and the background image of the start button should change.
Is there a way to do this with just javascript or do I need jquery?
It also doesn't seem possible to use onclick on div tags, jquery to do that aswell?
jsFiddle
You can use onclick on <div> tags. But you shouldn't use onclick on any tags. Don't confuse your HTML layout and display with your JavaScript functionality. Bind your click handlers directly in the JS code (note that this solution is using jQuery):
HTML:
<div id="button1">Button1</div>
<div id="button2">Button2</div>
<div id="button3">Button3</div>
<div id="startButton">Start</div>
JS:
function choose1() {
// ...
}
function choose2() {
// ...
}
function choose3() {
// ...
}
$(function() {
$("#button1").click(choose1);
$("#button2").click(choose2);
$("#button3").click(choose3);
});
You can do it in javascript (anything possible with jQuery is possible with plain javascript, since jQuery is written in javascript).
Changing the click handler for the startButton from javascript is very straightforward:
document.getElementById("startButton").onclick = newFunction;
Changing the background image is also pretty simple:
document.getElementById("startButton").style.backgroundImage = "image.png";
Obviously, you should replace newFunction and "image.png" with the function and image you actually want to use respectively.
You can say
function choose1() {
document.getElementById('startButton').onclick = function() {
alert("Button one was originally press");
}
}
jQuery IS javascript. It is just a library of functions/methods that you can call.
To solve your problem, you should write a function that changes the onclick property of your start button, and add the function you write to the onclick of the other buttons.
Like so:
function chooseOne(){
document.getElementById('startButton').onclick="/\*whatever\*/";
}
A technology like what #nbrooks said in the comments that would do this very well is AngularJS
If you give each selector button a class, you can use javascript to interate them and bind a click event. Then you can store in a data property a key which you can lookup in a json object start stores the related action handler and image. Finally in your click handler you can pull these properties and apply them to the start button by setting the onClick handler and background image of the start button.
<div class="startSelector" data-startdataid="1">Button1</div>
<div class="startSelector" data-startdataid="2">Button2</div>
<div class="startSelector" data-startdataid="3">Button3</div>
<div id="startButton">Start</div>
<script>
var startData = {
"1": {
action: function() {
alert("Button 1 was selected");
},
image: "/images/button1.jpg"
},"2": {
action: function() {
alert("Button 2 was selected");
},
image: "/images/button2.jpg"
},"3": {
action: function() {
alert("Button 3 was selected");
},
image: "/images/button3.jpg"
}
}
var changeStartButton = function(e) {
var startDataIndex = e.target.dataset.startdataid
var data = startData[startDataIndex]
document.getElementById("startButton").onclick = data.action
document.getElementById("startButton").style.backgroundImage = data.image
}
items = document.getElementsByClassName("startSelector")
for (var i = 0; i < items.length; i++) {
items[i].addEventListener("click", changeStartButton);
}
</script>
Example
http://jsfiddle.net/Xk8rv/3/

Why does the jQuery file upload stop working after first upload?

I'm using the jQuery File Upload plugin. I'm hiding the file input and activating it upon clicking a separate button. (See this fiddle.)
HTML:
<div>
<button class="browse">Browse</button>
<input id="upload" type="file" style="display: none;" />
</div>
JavaScript:
var element = $("#upload");
$(".browse").click(function () {
$("#upload").trigger("click");
});
element.fileupload({
add: function () {
alert("add");
}
});
Notice that if you press the button then select a file, the add method is activated and you'll get an alert. Do it again, and you'll get another alert.
Now, see this fiddle. The only difference is that I've changed the following line
$("#upload").trigger("click");
to
element.trigger("click");
Notice that now, the first time you click the button then select a file, the add method is activated and you get the alert (just like before), but if you do it again, the add method never activates.
What is causing this difference in behavior?
This can also be solved by setting replaceFileInput to false, as stated by the documentation. This is because the plugin recreates the input element after each upload, and so events bound to the original input will be lost.
It looks as though the scope of element is being lost / changed after the add function. Resetting it like below seems to work.
var element = $("#upload");
$(".browse").click(function () {
element.trigger("click");
});
element.fileupload({
add: function () {
alert("add");
element = $(this);
}
});
Fiddle
Try this one: http://jsfiddle.net/xSAQN/6/
var input = $("#upload");
$(".browse").click(function () {
input.trigger("click", uploadit(input));
});
function uploadit(input){
$(input).fileupload({
add: function () {
alert("add");
}
});
}
Although there is one more way:
just change to this:
var element = $("#upload");
$(".browse").click(function () {
$("#upload").click(); // <----trigger the click this way
});
element.fileupload({
add: function () {
alert("add");
}
});

Categories

Resources