Javascript fails to access a JSF component by calling through its id - javascript

I am trying out the following piece of code to get access a JSF component in Javascript by referring to its Id. But this fails.
JSF component:
<p:commandLink onclick="calculatePosition(this.id)" >
<h:graphicImage url="2.png"/>
</p:commandLink>
Javascript code:
<script type="text/javascript">
function calculatePosition(idOfClicked){
alert(idOfClicked);
var $element = jQuery('#'+idOfClicked);
var offset = $element.offset();
alert(offset.top);
}
</script>
1st alert works dislaying correct id of the element thereby proving that the JS function is called & correct id has been passed but it fails to display the 2nd alert. This happens only when the id of a JSF component is passed to this JavaScript function but works fine with non JSF components.
How can I make it work correctly ?

JSF prepends IDs of parent NamingContainer components (such as <h:form>) in generated client id with : as default separator character. So for example
<h:form id="foo">
<p:commandButton id="bar" />
...
will end up in generated HTML as
<form id="foo" name="foo">
<input type="submit" id="foo:bar" name="foo:bar" />
(rightclick page in webbrowser and choose View Source to see it yourself)
The : is however illegal in CSS identifiers. This was chosen so that the enduser won't accidently use it in component IDs which would only result in inaccessible parameters and components in the JSF side. To select an element with a : in the ID using CSS selectors in jQuery, you need to either escape it by backslash or to use the [id=...] attribute selector.
var $element1 = jQuery('#' + id.replace(':', '\\:'));
// or
var $element2 = jQuery('[id="' + id + '"]');
Alternatively, since JSF 2.0 you can override the ID separator character by a javax.faces.SEPARATOR_CHAR context parameter in web.xml with a different but CSS-valid value such as -. However, you need to be careful that you don't use this character yourself in any JSF component IDs.
As a completely different alternative, you can also just pass the whole HTML DOM element itself.
<p:commandButton onclick="calculatePosition(this)" />
so that you can do
function calculatePosition(element) {
var $element = jQuery(element);
// ...
}
without fiddling with IDs.

Related

Why would the value from a javascript selector be returned but undefined using jquery

I have a simple form called myForm I'm making as an exercise to get better at Javascript and jquery. Inside my form I have a set of radio buttons that act as boolean values to show or hide other content (in this case, 2 divs that contain a table).
I wanted to tidy up the code a bit using jquery selectors rather than the entire document.get javascript way. I'm doing this inside an ASP.NET Core 3.1 MVC application if that matters.
The following code correctly grabs the value of my radio buttons
My view
<div class="form-group">
<input type="radio" asp-for="AssignExtension" name="AssignExtension" value='true' onclick="assignExtensionSelect('true')" /> Yes
<input type="radio" asp-for="AssignExtension" name="AssignExtension" value='false' onclick="assignExtensionSelect('false')" /> No
</div>
site.js
<script>
function assignExtensionSelect(extRequired) {
let formInput = document.getElementById("myForm");
//let formInput = $("#myForm");
console.log(formInput.AssignExtension.value);
if (extRequired) {
$('#ifassignextension').show();
$('#ifnotassignextension').hide();
}
else {
$('#ifassignextension').hide();
$('#ifnotassignextension').show();
}
}
</script>
The commented line is the one that won't work correctly. Why does the code return undefined when I have formInput = $("#myForm"); but works as expected when I assign the variable using the document.getElementById syntax?
Note: I have jquery already included in the view and other functions already using it, so this is not a dependency issue or jquery not being loaded.
You're trying to use DOM properties with jQuery objects. If you're using jQuery, you have to use its selectors and methods.
let formInput = $("#myForm");
console.log(formInput.find("[name=AssignExtension]:checked").val());

Does primefaces fluidGrid provide a rowIndexVar or rowKeyVar attribute?

I am using a reponsive grid which is an extension of primefaces. However I can't seem to figure out how to get the index of items within the grid.
I tried rowIndexVar and rowKeyVar and they don't seem to work. I've included a snippet of my code below.
<pe:fluidGrid value="#{resultList}" var="showvar" rowKeyVar="rowKey" fitWidth="true" hasImages="true">
...
</pe:fluidGrid >
...
<h:link onclick="$(callme('#{showvar.showId}','#{rowKey}'));">
<h:graphicImage url="#{showvar.showImage}"/>
</h:link>
....
<h:outputScript>
function callme(id,row){
alert(id);
alert(row);
}
</h:outputScript>
I could just declare an unique index variable in my object and reference it like below, but I'd like to know if fluidGird offers a rowKeyVar attribute.
<ui:param name="itemIndex" value="#{showvar.showIndex}" />
I think what you are looking for is the varContainerId
varContainerId
Name of the request-scoped variable which contains the prefix of the client Id within pe:fluidGridItem. This property allows to get the whole clientId of a component within pe:dynaFormControl. The whole client Id is sometimes required for JavaScript or RequestContext.update(...).
See also: http://www.primefaces.org/showcase-ext/views/fluidGrid.jsf

How to submit a form by clicking a link javascript

currently I'm trying to make it so that when the user clicks a link it submits the corresponding form via javascript. I used document.getElementById("id").submit() as a basis on how to send the form so my code should act similar to it in my understanding.
Here's the code:
function run(clickedLink){
clickedLink.id.submit(); //I did it like this since document.getElementById just gets the form id and since link and form have similar id's I thought it would send
}
<form id = 'formId'>
<a href = '#' id = 'formId' onclick = run(this)>Link</a>
</form>
I tried going with name = 'formId' too but it still doesn't run as I wanted it too.
Note: doing this since this code iterates dynamically and the id gets updated i.e. formID1, formID2...
Better ways to implement this are welcome too
Modify your function as follows
function run(clickedLink){
clickedLink.parentNode.submit(); // parentNode refers to the form element
}
You cannot use same id on the same page for more than one element. This is against HTML and DOM specifications https://softwareengineering.stackexchange.com/questions/127178/two-html-elements-with-same-id-attribute-how-bad-is-it-really .
You can change it to class if you want to reuse or you can change the id itself of other element. Also links are not recommended to submit the form. Their job is to navigate
Try this:
<a href="#" onclick="document.forms[0].v.value='Link1';
document.forms[0].submit();">Link 1</a>
One Basic thing:
-ID's are used to Uniquely Describe The Element in DOM Hierarchy. Please Don't Repeat it. (it is really bad)
Now to the answer:
function run(x){
var y=findParentForm(x); /* if Id's aren't Unique */
// If iD's are Unique :- var y=document.getElementById("formId");
y.submit();
}
function findParentForm(elem){
/*
This function will find exact parent form
even if link or elem is inside <div> or other complex DOM structure
This will Only return the parent <form> of that elemnt
*/
var parent = elem.parentNode;
if(parent && parent.tagName != 'FORM'){
parent = findParentForm(parent);
}
return parent;
}
<form id='formId' action="Server Side Script" method="GET/POST">
Link <!-- change id of link -->
</form>

Getting JSF-defined component with Javascript

I'm creating an interface using JSF, and I'd like the value of one text field to provide the default for a second if the second hasn't yet been set. The crucial code will look something like this:
<h:outputScript>
function suggestValue2() {
var value2 = document.getElementById('value2').value;
if (value2 == "") {
document.getElementById('value2').value = document.getElementById('value1').value;
}
}
</h:outputScript>
<h:inputText
id="value1"
onblur="suggestValue2();" />
<h:inputText
id="value2" />
The problem is this doesn't actually work. The actual IDs of those two input elements get prefixed with some JSF-generated values, which tanks the getElementById calls. What's the best way for me to accomplish what I'm trying to accomplish here?
Edit: I should note that this is going to appear inside a composite component, which could wind up appearing multiple times on a single page. JSF dynamically setting the actual ID represents desired behavior.
Bind the component to the view,
<h:inputText binding="#{input1}" ... />
so that you can just print its client ID elsewhere in the view by UIComponent#getClientId().
<h:outputScript>
var input1 = document.getElementById('#{input1.clientId}');
// ...
</h:outputScript>
As you mentioned that you're inside a composite component, it may be good to know that composite component's own client ID is already available via #{cc.clientId}. So the more recommended alternative would be:
<cc:implementation>
<h:outputScript>
var input1 = document.getElementById('#{cc.clientId}:input1');
// ...
</h:outputScript>
...
<h:inputText id="input1" ... />
...
</cc:implementation>
See also:
Integrate JavaScript in JSF composite component, the clean way
Jsf uses a concept "naming containers" which says the id need not be unique within a provided container. Provided the container has an Id. So if you are not giving an Id to the container jsf appends the unpredictable values before the element. With id for container it becomes containerid:elements id. And this can be used in JavaScript reliably

In XForms, with Orbeon, how to update an XML instance through jQuery?

I want to perform some logic in JavaScript when users click on the span element and update current XML instance from jQuery:
(I have seen 2 similar questions online but they never got answered!)
XForms:
<xhtml:span class="buttonPlusOne" id="plusVat">+</xhtml:span>
<xf:output ref="instance('submitted_instance')/TotVATAmnt"></xf:output>
<xf:input id="changeVatTotal" ref="instance('submitted_instance')/TotVATAmnt"></xf:input>
JavaScript:
$('span.buttonPlusOne').on('click', function () {
// do some logic and increment value for 0.01
orbeonElId = $(this).siblings('#changeVatTotal').children('input').attr('id');
// alert(orbeonElId) produces right id (changeVatTotal$xforms-input-1)
// alert(newValue) produces 0.02 (for example)
ORBEON.xforms.Document.setValue(orbeonElId, newValue);
});
I can see Orbeon posting data (Firebug), but the XML Instance does not get updated (input does not update the output - even though they share same "ref" attribute).
I suppose that you're mixing up the html element's id with the XForms id (id attribute) of the xf:input element.
The Orbeon documentation shows an example: the id to use in the ORBEON.xforms.Document.setValue() function call is the id of the (server-side) XForms element. So in your example it's changeVatTotal, and not the id of the (client-side) html input element changeVatTotal$xforms-input-1. This is why there's a request showing up in firebug with no effect on the XForms instance: the server-side XForms engine doesn't find a xf:input element with the id changeVatTotal$xforms-input-1, so it doesn't know what to do with that request.
This means, too, that you (usually) don't need to compute the id of the target element, instead you can just use the "plain" XForms id attribute value of the xf:input.
Alternatively:
Is it possible to handle the "plus" button completely in XForms? You could use a xforms:trigger control and include a xforms:setvalue action on the DOMActivate event:
<xf:trigger>
<xf:label>+</xf:label>
<xf:setvalue
ev:event="DOMActivate"
ref="instance('submitted_instance')/TotVATAmnt"
value="0.01 + instance('submitted_instance')/TotVATAmnt" />
<.... more actions ...>
</xf:trigger>
I think this solution would be more stable than doing some of the work client-side and some server-side.

Categories

Resources