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>
Related
As I understand you can not change the props value directly in the child component.
But I find out that this will work, I want to know the reason behind it.
For reference: I am using vue3+vite
For example:
<template>
<input v-model="price"/>
</template>
<script lang="ts" setup>
defineProps({
price : Number
});
</script>
this can change the props value based on the input. with no warning or error
but if I write this way
<template>
<input v-model="props.price"/>
</template>
<script lang="ts" setup>
const props = defineProps({
price : Number
});
</script>
there will be a warning in the console.
notice I didn't write any computed to handle the change of the props.
Is it a bad practice?
Both should issue warning. The reasoning is that the parent will not usualy be aware of the change unless it is mutated there. It also allows the parent to validate the change. The idea is that only the owner of the data should modify it.
So emit an event instead. The conventional way to write the code is.
<input :value="price" #input='$emit("input", $event)'/>
// or
<input :value="price" #update:value='$emit("update:value", $event)'/>
// or
<input :value="price" #input='$emit("update:value", $event)'/>
You can access both because Vue automatically exposes both the props object itself and all the props' properties into the template.
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).
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).
Problem: Sometimes you will want to access a component from javascript with
getElementById, but id's are generated dynamically in JSF, so you
need a method of getting an objects id. I answer below on how you can do this.
Original Question:
I want to use some code like below. How can I reference the inputText JSF component in my Javascript?
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<head>
<title>Input Name Page</title>
<script type="javascript" >
function myFunc() {
// how can I get the contents of the inputText component below
alert("Your email address is: " + document.getElementById("emailAddress").value);
}
</script>
</head>
<h:body>
<f:view>
<h:form>
Please enter your email address:<br/>
<h:inputText id="emailAddresses" value="#{emailAddresses.emailAddressesStr}"/>
<h:commandButton onclick="myFunc()" action="results" value="Next"/>
</h:form>
</f:view>
</h:body>
</html>
Update: this post Client Identifiers in JSF2.0 discusses using a technique like:
<script type="javascript" >
function myFunc() {
alert("Your email address is: " + document.getElementById("#{myInptTxtId.clientId}").value);
}
</script>
<h:inputText id="myInptTxtId" value="backingBean.emailAddress"/>
<h:commandButton onclick="myFunc()" action="results" value="Next"/>
Suggesting that the attribute id on the inputText component
creates an object that can be accessed with EL using #{myInptTxtId},
in the above example. The article goes on to state that JSF 2.0 adds
the zero-argument getClientId() method to the UIComponent class.
Thereby allowing the #{myInptTxtId.clientId} construct suggested
above to get the actual generated id of the component.
Though in my tests this doesn't work. Can anyone else confirm/deny.
The answers suggested below suffer from drawback that the above
technique doesn't. So it would be good to know if the above technique
actually works.
You need to use exactly the ID as JSF has assigned in the generated HTML output. Rightclick the page in your webbrowser and choose View Source. That's exactly the HTML code which JS sees (you know, JS runs in webbrowser and intercepts on HTML DOM tree).
Given a
<h:form>
<h:inputText id="emailAddresses" ... />
It'll look something like this:
<form id="j_id0">
<input type="text" id="j_id0:emailAddress" ... />
Where j_id0 is the generated ID of the generated HTML <form> element.
You'd rather give all JSF NamingContainer components a fixed id so that JSF don't autogenerate them. The <h:form> is one of them.
<h:form id="formId">
<h:inputText id="emailAddresses" value="#{emailAddresses.emailAddressesStr}"/>
This way the form won't get an autogenerated ID like j_id0 and the input field will get a fixed ID of formId:emailAddress. You can then just reference it as such in JS.
var input = document.getElementById('formId:emailAddress');
From that point on you can continue using JS code as usual. E.g. getting value via input.value.
See also:
How to select JSF components using jQuery?
Update as per your update: you misunderstood the blog article. The special #{component} reference refers to the current component where the EL expression is been evaluated and this works only inside any of the attributes of the component itself. Whatever you want can also be achieved as follows:
var input = document.getElementById('#{emailAddress.clientId}');
with (note the binding to the view, you should absolutely not bind it to a bean)
<h:inputText binding="#{emailAddress}" />
but that's plain ugly. Better use the following approach wherein you pass the generated HTML DOM element as JavaScript this reference to the function
<h:inputText onclick="show(this)" />
with
function show(input) {
alert(input.value);
}
If you're using jQuery, you can even go a step further by abstracting them using a style class as marker interface
<h:inputText styleClass="someMarkerClass" />
with
$(document).on("click", ".someMarkerClass", function() {
var $input = $(this);
alert($input.val());
});
Answer: So this is the technique I'm happiest with. Doesn't require doing too much weird stuff to figure out the id of a component. Remember the whole point of this is so you can know the id of a component from anywhere on your page, not just from the actual component itself. This is key. I press a button, launch javascript function, and it should be able to access any other component, not just the one that launched it.
This solution doesn't require any 'right-click' and see what the id is. That type of solution is brittle, as the id is dynamically generated and if I change the page I'll have to go through that nonsense each time.
Bind the component to a backing bean.
Reference the bound component wherever you want.
So here is a sample of how that can be done.
Assumptions: I have an *.xhtml page (could be *.jsp) and I have defined a backing bean. I'm also using JSF 2.0.
*.xhtml page
<script>
function myFunc() {
var inputText = document.getElementById("#{backBean.emailAddyInputText.clientId}")
alert("The email address is: " + inputText.value );
}
</script>
<h:inputText binding="#{backBean.emailAddyInputText}"/>
<h:commandButton onclick="myFunc()" action="results" value="Next"/>
BackBean.java
UIInput emailAddyInputText;
Make sure to create your getter/setter for this property too.
Id is dynamically generated, so you should define names for all parent elements to avoid j_id123-like ids.
Note that if you use jQuery to select element - than you should use double slash before colon:
jQuery("my-form-id\\:my-text-input-block\\:my-input-id")
instead of:
jQuery("my-form-id:my-text-input-block:my-input-id")
In case of Richfaces you can use el expression on jsf page:
#{rich:element('native-jsf-input-id')}
to select javascript element, for example:
#{rich:element('native-jsf-input-id')}.value = "Enter something here";
You can view the HTML source when this is generated and see what the id is set to, so you can use that in your JavaScript. As it's in a form it is probably prepending the form id to it.
I know this is not the JSF way but if you want to avoid the ID pain you can set a special CSS class for the selector. Just make sure to use a good name so that when someone reads the class name it is clear that it was used for this purpose.
<h:inputText id="emailAddresses" class="emailAddressesForSelector"...
In your JavaScript:
jQuery('.emailAddressesForSelector');
Of course you would still have to manually manage class name uniqueness.
I do think this is maintainable as long as you do not use this in reusable components. In that case you could generate the class names using a convention.
<h:form id="myform">
<h:inputText id="name" value="#{beanClass.name}"
a:placeholder="Enter Client Title"> </h:inputText>
</h:form>
This is a small example of jsf. Now I will write javascript code to get the value of the above jsf component:
var x = document.getElementById('myform:name').value; //here x will be of string type
var y= parseInt(x,10); //here we converted x into Integer type and can do the
//arithmetic operations as well
I was wondering if its possible to override existing HTML Element attribute and property accessors (getters and setters) with Javascript so that when html is rendered by browser all the assignments to certain attributes in the html code are preprocessed with custom functionality.
Here is an example :
<html>
<head>
<script>
// JS code would go here which would override default behavior
// for example if I wanted to reformat id="name" so its actually
// registered as id="pre_name" once browser renders the html
</script>
</head>
<body>
<!-- here we are assigning the 'name' to id , but behind the scene we really want it to be 'pre_name' -->
<div id="name"></div>
<script>
// when we try to access the id it would actually match the overwritten one
console.log(document.body.children[0].id) // would output pre_name
</script>
</body>
</html>
Is something like that possible and how?
I know that I can traverse the dom after it's rendered and change all of the ids, but I am wondering if its possible to intercept the assignment of properties and attributes and do it at that level before browser even renders the html.
Example I presented is just made up one to present the problem and make is simple to understand.
Thanks
Unfortunately this is not possible, you can only modify the name element after it is loaded.
So it would be something like this:
<body>
<!-- here we are assigning the 'name' to id , but behind the scene we really want it to be 'pre_name' -->
<div id="name"></div>
<script>
// right after
document.getElementById('name').id = 'pre_name';
</script>
<script>
// when we try to access the id it would actually match the overwritten one
console.log(document.body.children[0].id) // would output pre_name
</script>
</body>
or even
<body>
<!-- here we are assigning the 'name' to id , but behind the scene we really want it to be 'pre_name' -->
<div id="name"></div>
<script>
// or here
document.getElementById('name').id = 'pre_name';
// when we try to access the id it would actually match the overwritten one
console.log(document.body.children[0].id) // would output pre_name
</script>
</body>
You can use html data-* attributes for second value like;
<div id="name" data-second="pre_name"></div>
And then you can use,
var div = document.getElementById('name');
div.getAttribute("data-second");