This is a continuation of an issue I was having yesterday so if it looks familiar, thats why :) It IS a different question tho!
So I have another dijit.form.Select initially created on the page like so;
<c:set var="clazzId" value="${verification.clazz.id}" />
<div id="clazzOptions">
<select id="clazz" name="clazz" style="width:22em" dojoType="dijit.form.Select" maxHeight="140">
<option value="-1" label=" " />
<c:forEach items="${requestScope.clazzes}" var="clazzItem">
<c:choose>
<c:when test="${clazzId eq clazzItem.id}">
<option value="${clazzItem.id}" selected = "true">${clazzItem.name}</option>
</c:when>
<c:otherwise>
<option value="${clazzItem.id}">${clazzItem.name}</option>
</c:otherwise>
</c:choose>
</c:forEach>
</select>
</div>
I then have some javascript that I'm trying to use to swap the contents of the div "clazzOptions" depending on the value chosen from a different drop down (not seen here). If its a certain value, replace the div with a text message, if its any other value, re-show the original dijit.form.Select;
<script type="text/javascript">
var classDropDown;
var classPhDMessage = "PhD's do not require a Class or Grade";
dojo.addOnLoad(function() {
classDropDown = dojo.byId('clazzOptions').innerHTML;
});
function checkForPHD() {
var awardOption = dijit.byId('qualification').attr('displayedValue');
if(awardOption == "PhD"){
dojo.byId('clazzOptions').innerHTML = classPhDMessage;
} else {
dojo.byId('clazzOptions').innerHTML = classDropDown;
}
}
</script>
As you can see I'm trying to capture the innerHTMLof the div as it is when the page loads and then depending on the value chosen in the other drop down (not seen) change between a predefine message and the captured div contents.
The issue is that after the original div contents have been replaced with the message and then the selection changes again away from "PhD" and the original div innerHTML is placed back into the div, the dijit.form.Select re-appears but is completely empty and in fact doesn't appear usable at all? If I remove the dijit.form.Select dojoType and just leave it as a normal select this whole operation works perfectly but I kinda need it to be a dijit.form.Select.
Why won't dijit.form.Select work in this case whereas a normal select does?
You shouldn't use innerHTML to add/remove dijits, especially if you're trying to re-use them.
A dijit is a combination of HTML and Javascript and can be thought of as 'more complex' than simply the contents of a specific node.
You have a number of options:
Disable your dijit.form.Select and add a small note under it (or set it's value) explaining why it's disabled (this is generally a better UI paradigm than removing controls). Depending on your UI this is what I'd try and do
Create a <span> as a sibling of your dijit.form.Select and use CSS to show/hide one of them at a time.
Obviously you'll still get the value of the dijit.form.Select when you submit your form, but because you do server side validation as well as client side validation (I hope :) this won't be a problem
Use the dojo.data API to create a datastore from your "${requestScope.clazzes}" iterator. Use this store when you (programatically) create the dijit.form.Select. Keep track of the current value of said Select somewhere. When you don't need it, call yourSelect.destroy() to properly destroy it, then when you need it again create a new one and set it's value to the saved value from before.
This seems unnecessarily expensive to me tho.
Related
unfortunately this is a project for school and most of the variables are in my native language, i'll translate any if needed, but leave the code as is, just in case that's somehow the problem.
I'm making a web app for a Catering Service, using Java servlets for my backend and JSP for my front end.
The session stores an Order object which has a HashMap<Product, Quantity>.
On my Cart jsp foreach Product in the hashmap there's a row in the css grid displayed on the screen.
<!-- Cart jsp snippet-->
<!--article Order.getHashMap().keySet()-->
<c:forEach var="stavka" items="${Narudzbina.getStavkeNarudzbine().keySet()}">
<div class='korpa-stavka'>
<!-- article.getName() -->
<h5>${stavka.getNazivProizvoda()}</h5>
<input class="btn btn-light poeni-korpa" type="number" min="1" id="${stavka.getProizvodID()}" onchange="updateUrl(this)" value="${Narudzbina.getStavkeNarudzbine().get(stavka)}">
<div class="stavka-buttons">
<!-- Link is filled with a js script -->
Izmeni
<!-- Link is static except for the ID, but no JS -->
IzbriĆĄi
</div>
</div>
<p class='stavka-total'>Cena: ${stavka.getCenaPoPorciji() * Narudzbina.getStavkeNarudzbine().get(stavka)} RSD</p>
</c:forEach>
This works as intended.
One of the a tags href value is filled with an onchange call from the number input before it.
// Js for updating href of that a tag
function updateUrl(element){
var link = document.getElementById("a" + element.id);
link.setAttribute("href", "Korpa?Zahtev=Izmeni&Proizvod="+ element.id +"&Kolicina=" + element.value);
}
That also works well, for every auto generated row from the hashtable. Clicking on the a button on any of them, as far as i can see, correctly calls the "Korpa" Controller, with good parameters, different, and correct ArticleID, different and correct Quantity for each of them.
Korpa servlet then packs the session Order object in a temporary Order, calls changeQuantity(article, newQuantity) on it, when that's done packs the changed Order in session and reloads the cart page..
// Order order = session order
Narudzbina narudzbina = (Narudzbina)session.getAttribute("Narudzbina");
//order.change quantity
narudzbina.izmeniKolicinu(Integer.valueOf(request.getParameter("Proizvod")), Integer.valueOf(request.getParameter("Kolicina")));
session.setAttribute("Narudzbina",narudzbina);
//refreshes the Cart jsp
response.sendRedirect("Profil?User=" + session.getAttribute("User").toString() + "&View=Korpa");
return;
The Order Model just changes the value in the hash map
//changeQuantity article ID newQuantity
public void izmeniKolicinu(int proizvodID, int novaKolicina) {
//Order ord : hashMap.keySet()
for (Proizvod prod : stavkeNarudzbine.keySet()) {
//if ord.getArticleID == articleID
if (prod.getProizvodID() == proizvodID) {
stavkeNarudzbine.put(prod, novaKolicina);
}
break;
}
}
Now all of this works perfectly well for both changing quantity and deleting the article ( deleting is almost identical and there's a switch statement in the Controller to check what to run, i ommited that since this is already a long post, and it's very likely irrelevant )
But only for the first article drawn on the cart jsp screen.
The other articles properly update their respective href's, and all properly call the servlet, the page refreshes, there's no exceptions thrown, and the status of the request is 302 for both the 1st one ( that works ) and the rest. But the values do not update.
Clicking on any but the first generated link doesn't update values
Also if i click on Remove on the first one that actually works, it gets removed, and the new first drawn one works now.
Sorry for the rambling question, I'm just a student, really lost on this one, not really quite sure what the problem could be so I gave all the info i thought would be in any way helpful...
P.S There's no communication with the database anywhere in this process.
EDIT: Clarified problem
To have a proper answer here (the OP found it through the comments): the break needs to be within the if-condition
if (prod.getProizvodID() == proizvodID) {
stavkeNarudzbine.put(prod, novaKolicina);
break; // HERE
}
// NOT HERE: break;
I'm looking to send information after each link click to my java class to help increment a counter and to change an object which is held in my bean (myGame) which holds an array of 'cases'. I understand that I can increment a counter using JS, but i'd like to keep all game logic within the bean if possible.
I have considered using forms and changing the anchor to a submit button, however, I'd like to keep that the player can no longer click the link after it the case is eliminated.
The printCase(int) function works by finding the corresponding case in the array, checking the value of a boolean (is the case is eliminated from the game [deal or no deal]) and then prints the amount of money held in the case if eliminated; the case number if it is not.
I have about a dozen cases.
<jsp:useBean id="myGame" scope="session" class="dealOrNoDeal.GameLogic"/>
<table border="1" id="dndTable">
<form action="/../doStuff.jsp" method="post">
<tr>
<td> <%= myGame.printCase(0) %> </td>
</tr>
</form>
</table>
I've also considered changing my bean to a servlet. Does that work? Can you have a bean in a servlet?
Thanks all.
Update: I've made printCase now print the tag that it's within now, as well. Prints as a submit button if the case is not opened, prints as a <p> if it is (I need it to use the class). Attempted putting the <td>s in there as well, but it somehow messes up the formatting.
I'm now looking to get the name of the one button that was clicked, any ideas?
I'm not sure about understand completely your qestion. But i'll try:
U have 2 ways:
You have to build a jquery where on each button click u call a servlet where u send information to your java class;
Using DWR: http://directwebremoting.org/dwr/index.html
Unfortunately, I made a mistake of choosing JSF for an internet facing, high traffic application, now I am wondering as to how to improve the scalability of this JSF webapp.
I have a JSF page that displays a large no of items each of which may be commented upon.
Inorder to reduce the state & improve performance I am trying to reduce the no of forms /commandButtons on the page.
1. Through what ways can I reduce the component tree/ statefulness of JSF ? Do the plain html elements(that are mixed in between the jsf tags) also form part of component tree ? I dont know how component state saving has been helpful to my app since I have been following plain request/response model while designing my app, (may be it is helpful for just JSF's internal requirements)!?
2. I was thinking of an approach where instead of creating a separate <h:form> (each with a separate commandButton) for every item like below,
(Usual Approach)
<h:form> <!-- for each item a separately -->
<h:outputText value="Add comment"/>
<h:inputTextarea value="#{itemController.comment}" required="true"/>
<p:commandButton actionListener="#{itemController.addUserComment(123)}" value="Add" />
</h:form>
(Alternate Approach)
I am trying to make the above better by just putting a single remoteCommand for all the items & pass the required parameters to this remoteCommand.
<form>
<input id="item1_comment"/>
<button onclick="addComment(123, 'item1_comment');"/>
</form>
<script type="text/javascript">
function addComment(itemId, id) {
$('#comment_in').attr('value', $('#'+id).attr('value'));
$('#forItem_in').attr('value', itemId);
addComment_RC(); // call remoteCommand to show the content in dialog
}
</script>
<h:form prependId="false" > <!-- for all items, just single remoteCOmmand -->
<h:inputHidden id="comment_in" value="#{itemController.comment}"/>
<h:inputHidden id="forItem_in" value="#{itemController.forItem}"/>
<p:remoteCommand name="addComment_RC" process="#form" actionListener="#{itemController.addComment()}" />
</h:form>
Is it better to do it this way (or are there any issues with this approach)?
Performance issues in the situation you describe are often caused by the large number of EL expressions, That burdens the server.
One approach to tackle this issue is to compute the comments on the client side, and pass them all at once to the server. Thus reducing the number of comment EL expression to one or none, and use only one button.
Place all the elements in one form. The comments fields are not binded.
<h:form>
// first element
<h:outputText value=#{first element}
// first comment
<h:inputTextarea id="comment1"/> <-- notice there is no EL expression
But we use a unique id for each comment
// second element
<h:outputText value=#{second element}
// second comment
<h:inputTextarea id="comment2"/>
.
.
.
</h:form>
From here you could either
1. after each blur event in any of the comment fields, ajax the server and pass as parameters the comment and the id of the comment from which the ajax call was made. on the server update your model accordingly
Or You can also gather all the comments on the client side and send them to the server at one time.
2. When the user press the submit button call a js function to aggregate all the comments in a structure that you will be able to parse easily on the server side
(ie. "{c1,comment a};{c2,comment b};{c5=,comment e}...").
pass that string to the server, parse it and update your model accordingly.
3. after each blur event in any of the comment fields, call a js function that updates an hidden field.
<h:inputHidden value="{myClass.allComments}" />
when the user submits the form parse allComments and update your model accordingly.
EDIT:
To address the general performance issue I've added recommendations from an article that I found helpful speed up part 1 Speed up part 2.
Hope this helps
btw, I would recommend the first approach rather than the last two.
I have disabled=true textboxes and combox boxes in my jsp.
When I try to map those value back to action, they disappear.
I don't want to call to DB again.
How can I set those disabled=true textboxes and combo boxes's data value into hidden values?
Thanks ahead.
The property of disabled elements' value not being submitted with the form is not an issue with struts2, but an HTML behavior. To handle this behavior, use the following implementations:
Use readonly="readonly" attribute to prevent modification rather than using disabled. (This won't be available for few elements)
Use onfocus="return false" to prevent any focus on html elements. This will prevent the modification of their value. You can use CSS to make these elements look like readonly or disabled.
Before you disable an element, create a hidden element and attach the value of the element you are about to disable. This will make sure that the item gets submitted.
See the following implementation for select element. You may make use of the id attribute of s:select to set the html id of select element.
<select id="demoSelect" class="readonly">
<option value="0">A</option>
<option value="1">B</option>
<option value="2" selected="selected">C</option>
<option value="3">D</option>
<option value="4">E</option>
<option value="5">F</option>
</select>
<input type="hidden" value="2" name="demoSelectDefault"/>
jQuery:
$(document).ready(
function() {
$("select.readonly").live('change', function() { //live() makes sure that this is executed if you apply the class to the element even after the initial load. So, if you set the readonly class to a select element, you are done.
var selectElement = this;
$("input[type=hidden][name=" + this.id + "Default]").each( //This is implemented in case of multiple select support. You will need to select nothing at first and then make this select each of this element
function() {
selectElement.value = this.value;
}
);
});
}
);
Here, when you implement this using struts, populate the s:select, then use an s:hidden element to generate a corresponding default value.
<form jwcid="#Form" listener="listener:updateStaff">
<select jwcid="staffselect#Select" multiple="ognl:false" validators="validators:required" onchange="this.form.submit()" listener="listener:updateStaff">
<span jwcid="#For" source="ognl:hrStaff" value="ognl:currentHrStaff" index="ognl:currentHrStaffIndex">
<option class="text11" jwcid="#Option" selected="ognl:hrStaffSelection[currentHrStaffIndex]" label="ognl:currentHrStaff"/>
</span>
</select>
</form>
when onchange on selectbox, this form will be submitted and my pageValidate() will be called follow by upadteStaff() listener method. I wonder, when such submission is fired, can onchange='' pass a flag ('selectboxisfired' string) that i able to capture inside pagevalidate() 'selectboxisfired'? this will allow my logic inside pagevalidate to indicate is triggered by selectbox.
onchange="window.submitTrigger=this; this.form.submit();"
Then you can read the window.submitTrigger variable in your validation routines to work out which element triggered the submission, for example
/* somewhere in pagevalidate() routine */
/* note here that I am assuming the html id of the selectbox is "staffselect"
-> I'm not familiar with Tapestry so simply had to make the assumption
that this is the correct id - if not, change the string you're searching
for accordingly */
if (window.submitTrigger.id = "staffselect") {
//do something here
}
Of note, is that I think it's bad style to use onchange in this way, however not understanding Tapestry, I'm just giving you the most simple change to what's already there which I assume will work...