Suppose I have an HTML button with onclick attribute and its value is calling a function(say fn).
function fn() {
document.querySelector("#greeting").innerHTML = "Hello folks";
}
<button type="button" onclick="fn()">Try it</button>
<p id="greeting"></p>
Question: What is the type of onclick attribute? I mean does onclick wants the result of the function call? From the above example, it seems that onclick attribute needs the result of the function call.
React example:
const { useState } = React;
function App() {
const [greeting, setGreeting] = useState("");
function fn() {
setGreeting("Hello Folks");
}
return (
<div>
<button type={"button"} onClick={fn}>
Try out
</button>
<p> {greeting} </p>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
In the react example, onClick attributes want a function not the result of the function.
What I have concluded from both the examples is: onclick wants the result of the function and onClick wants a function.
They are different though it does the same work.
From the HTML specification:
Event handler content attributes, when specified, must contain valid JavaScript code which, when parsed, would match the FunctionBody production after automatic semicolon insertion.
From the React documentation:
With JSX you pass a function as the event handler, rather than a string.
They are different though it does the same work.
Yes. HTML and JSX are different languages used to construct a DOM.
React is not using HTML directly, the syntax is similar but it's something else and yes it is HTMLish.
This funny tag syntax is neither a string nor HTML.
says here.
You don't get to write HTML inside javascript, you just utilize HTMLish type of syntax and write in react. And even though you use javascript, the flow of the react is a lot different than that of a normal web HTML/JS application (in terms of writing).
Related
I know how to pass data from a parent component to a livewire component, but how to do it, if the value is dynamic and generated by JavaScript?
<x-my-layout>
<livewire:my-component id="test" foo="this value should be passed" />
#push('scripts')
<script>
const livewireComponent = document.getElementById('test'); // <-- this is not working
livewireComponent.setAttribute('foo', 'bar'); // <-- In consequence this is not working
</script>
#endpush
</x-my-layout>
Please don't answer, that I just can use <livewire:my-component foo="bar" />, because I need to pass a value that is generated on client side like an text input.
Blade-components are rendered server-side, and thus you cannot set that property via Javascript like that. You would have to emit an event instead. Here are some examples on how you can do that. All of these following examples that are event-based, which means that you would have to listen for it within your component by adding
protected $listeners = ['setFooProperty'];
public function setFooProperty($value)
{
$this->foo = $value;
}
Using Alpine.js with x-init
<x-my-layout>
<div x-data x-init="Livewire.emit('setFooProperty', 'bar')">
<livewire:my-component id="test" foo="this value should be passed" />
</div>
</x-my-layout>
Using a global emit event with JavaScript
<x-my-layout>
<div x-data x-init="$wire.emit('setFooProperty', 'bar')">
<livewire:my-component id="test" foo="this value should be passed" />
</div>
#push('scripts')
<script>
Livewire.emit('setFooProperty', 'bar');
// or
Livewire.emitTo('my-component', 'setFooProperty', 'bar');
</script>
#endpush
</x-my-layout>
I had a form component with the following content
function Form() {
return (
<div className="form-container">
<div className="form-control">
<label id="text-input">Text </label>
<input type="text"></input>
</div>
<div className="form-control">
<label>Time </label>
<input type="text"></input>
</div>
<div className="form-control" style={{alignItems:"center"}}>
<button className="add-but">Add</button>
</div>
</div>
)
}
I wanted to focus the text element after the component gets rendered.
I was first trying to put {document.querySelector("#txt-in").focus()}, it didn't work and after searching I found I could use the tag autoFocus. and everything would work beautifully.
But I was wondering, what if I want to actually execute javascript code after rendering? or actually do this in javascript? I found answers for class based components but couldn't find for function based components like the one I am using.
how do I execute code I want executed after the element is rendred, in function based components?
You can use React Hooks useEffect for your purpose.
Simply put below code
import React, {useEffect} from "react";
function Form() {
useEffect(() => {
// Do whatever you want after first render
// Put your code here
}, [])
}
Similar to what the components are writing, previously one would use functions likecomponentDidUpdate & componentDidMount to manipulate components after/before being rendered. Funcitonal components realised we could use one 'hook' for this called useEffect where one can trigger a particular action to occur on the basis of a state change to the component.
Here is a link to the docs for useEffect - https://reactjs.org/docs/hooks-effect.html
I noticed this odd behavior while writing some demonstration code today, and I'm curious what's happening. "Button" does not work although "Button 2" does, even though they're being set in just different ways. I know it has to do with the quoting, but I'm curious why this is happening. Similarly, if I pass in a function to button 3 in quotes vs appending it directly in button 4, button 4 works but button 3 doesn't.
Also, I would think that given that button 2 works, it would do the evaluation of console.log("test") immediately (similar to how it would work without the quotes) but rather it delays until actually clicking on the button. I know this is not the best way to do it but for curiosity sake, I'm curious what's happening exactly here.
document.getElementById("app").innerHTML = `
<h1>Testing Sandbox</h1>
<div>
<button id='hello'>Button</button>
<button id='hello2' onclick='console.log("test")'>Button 2</button>
<button id='hello3' onclick='(e) => console.log("test")'>Button 3</button>
<button id='hello4'>Button 4</button>
</div>
`;
document.getElementById("hello").onclick = 'console.log("test")';
document.getElementById("hello4").onclick = (e) => console.log("test");
<!DOCTYPE html>
<html>
<head>
<title>Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app"></div>
<script src="src/index.js">
</script>
</body>
</html>
When you assign to onclick, you invoke a setter, which does something pretty similar to calling addEventListener with the assigned expression. But both addEventListener and onclick will silently fail if the passed expression is not a function:
document.getElementById("app").innerHTML = `
<h1>Testing Sandbox</h1>
<div>
<button id='hello'>Button</button>
`;
document.getElementById("hello").onclick = 'console.log("test")';
// nearly the same thing as:
document.getElementById("hello").addEventListener('click', 'console.log("test")');
<div id="app"></div>
The string does not get implicitly coerced to a function.
In the third example, the inline handler declares a function, but never executes it:
<button id='hello3' onclick='(e) => console.log("test")'>Button 3</button>
which is like
button.addEventListener('click', function(event) {
(e) => console.log("test")
});
The listener runs, but the listener doesn't contain anything other than an unused function expression, so you don't see anything when you click. This might be clearer if you add a log statement:
<button id='hello3' onclick='console.log("listener running;"); (e) => console.log("test")'>Button 3</button>
In general, you should never use inline handlers; they require global pollution, are hard to manage, have string and HTML escaping issues, and are pretty much universally considered to be bad practice. Instead, use addEventListener, and always pass it functions, not strings, for a listener to be properly added.
Why button two works ?
It is possible to associate an action with a certain number of events
that occur when a user interacts with a user agent. Each of the
"intrinsic events" listed above takes a value that is a script. The
script is executed whenever the event occurs for that element. The
syntax of script data depends on the scripting language. HTML Specs
So onclick = script [CT] will be called whenever user interacts, in this case it is an mouse click event
Why button don't work ?
document.getElementById("hello").onclick expects a function where as you're passing string
I have a class App that extends React.Component, in App there is the following render() code
render() {return(
<div style={styles}>
<button type="submit" value="Go" onClick=" alert('Hi') ">Go</button>
</div>
)}
replacing the quotations with curly brackets make the code work
<button type="submit" value="Go" onClick={ alert('Hi') }>Go</button>
I know that in React we should use { } if we want to add JavaScript code, but in this case we already can write HTML like this onClick=" alert('Hi') " so why this is not working?
Passing javascript as a string is not recommended for security / optimization issues.
Also, the development experience is better when the IDE knows how to differentiate between regular strings and JS code.
For those reasons, React does not allow you to use it like that.
Also, remember, JSX is not HTML. It is XML built for React, so not all HTML tags, attributes and nesting work in JSX and vice-versa.
What I ultimately want is to retrieve the innerHTML of the example script below (the html is to be put in a database). It must include the onclick events also. However in the generated HTML there is no onclick event available.
<html>
</head>
<script>
function test() {
this.goodbye="goodbye!";
this.elem=document.createElement('div');
this.elem.style.border='1px solid #888888';
this.elem.textContent="hello";
this.elem.style.cursor='pointer';
var that=this;
this.elem.onclick=function(){that.say_goodbye();}
document.getElementsByTagName('body')[0].appendChild(this.elem);
}
test.prototype.say_goodbye=function(blockid) {
this.elem.textContent=this.goodbye;
}
</script>
</head>
<body>
<script>var obj = new test();</script>
get html
</body>
</html>
the line of importance is thus:
this.elem.onclick=function(){that.say_goodbye();}
I tried to add it as attribute like:
this.elem.setAttribute('onclick',that.say_goodbye.bind(that));
But is doesn't work. When I click the link in the given code the browser alerts:
<div> onclick="function(){[native code]}" ..... </div>
In this case the HTML now has an 'onclick' event but contains '[native code]' as action.
Anyone an idea on how to make the code work?
The reason you get this is that attribute value is text always and you are trying to put object into it (functions are objects). This case you should rather use this.elem = that.say_goodbye.bind(that).