In the jsp page, I have a <s:optiontransferselect> for swap values between left side and right side and a submit button to save.
<s:optiontransferselect
allowUpDownOnLeft="false"
allowUpDownOnRight="false"
allowSelectAll="false"
allowAddAllToLeft="false"
allowAddAllToRight="false"
addToRightLabel="Go to right"
addToLeftLabel="Go to left"
leftTitle="Left side values"
headerKey="0"
name="option"
list= "optionList"
rightTitle="Right side values"
doubleHeaderKey="0"
doubleList="selectedOptionList"
doubleName="selectOption"
doubleId="selectedValues"
>
</s:optiontransferselect>
<s:submit />
I run the program, it actually can save the value from the right side. However it does not show the saved values there.
I am thinking about using javascript and use onchange event in <s:optiontransferselect> to achieve this
<script>
function show(){
const list = document.getElementById("selectedValues");
for (var i = 0; i < list.options.length; i++) {
//seems something not correct in this part but I am not sure how solve in this way
list.options[i].selected = true;
}
return true;
}
</script>
<s:optiontransferselect
allowUpDownOnLeft="false"
allowUpDownOnRight="false"
allowSelectAll="false"
allowAddAllToLeft="false"
allowAddAllToRight="false"
addToRightLabel="Go to right"
addToLeftLabel="Go to left"
leftTitle="Left side values"
headerKey="0"
name="option"
list= "optionList"
rightTitle="Right side values"
doubleHeaderKey="0"
doubleList="selectedOptionList"
doubleName="selectOption"
doubleId="selectedValues"
onchange ="show()" <!-- onchange seems not work here -->
>
</s:optiontransferselect>
When I run the program, the right side still cannot show the saved value.
More information about the optiontransferselect in case it is useful.
I have an action class for it.
public class OptionTransferSelectAction extends ActionSupport {
private List<String> optionList;
private List<String> selectedOptionList;
//private String option;
private List<String> option;
private List<String> selectOption;
public OptionTransferSelectAction (){
optionList=new ArrayList<String>();
//display on the left side for selection
optionList.add("Section A");
optionList.add("Section B");
optionList.add("Section C");
optionList.add("Section D");
optionList.add("Section E");
optionList.add("Section F");
optionList.add("Section G");
optionList.add("Section H");
selectedOptionList=new ArrayList<String>();
//display on the right side
//pretend it does not have any values in the first time (does not
//trigger the save yet)
}
public List<String> getOptionList() {
return optionList;
}
public void setOptionList(List<String> optionList) {
this.optionList = optionList;
}
public List<String> getSelectedOptionList() {
return selectedOptionList;
}
public void setSelectedOptionList(List<String> selectedOptionList) {
this.selectedOptionList = selectedOptionList;
}
/*
public String getOption() {
return option;
}
public void setOption(String option) {
this.option = option;
}
*/
public List<String> getOption() {
return option;
}
public void setOption(List<String> option) {
this.option = option;
}
public List<String> getSelectOption() {
return selectOption;
}
public void setSelectOption(List<String> selectOption) {
this.selectOption = selectOption;
}
}
update
I change option from String to List<String> with the proper getter and setter. I run the code, the optiontransferselect still cannot show the saved values.
Which part I did wrong? Would someone let me know please? Thank you.
update
I created a new jsp for example, success.jsp. If I selected some values to selectOption and click the submit button. the jsp file can display the values that I just submitted. I can see the saved values in the database. However the optiontransferselect still cannot show the saved values.
The success.jsp has one code which can display the value I have just submitted.
Selected Value(s) : <s:property value="selectOption"/>
In the database, I can see the saved values, so I would like to know how to let the optiontransferselect show the saved values?
another update
I try to use a button to call javascript function to show selectedValues before submit.
<script>
function testshow() {
var value = document.getElementById("selectedValues");
for(var i=0;i<value.options.length; i++) {
alert(value.options[i].innerHTML);
}
return true;
}
</script>
//button to call the function
<s:submit onclick="return testshow()"/>
I run the program, when I click the button, it can show the selected values before submit, so I still don't understand why the optiontransferselect cannot get saved selected values.
I think there are two things you need to know in order to solve your issue:
The lifetime of a Struts action.
How the optiontransferselect actually works.
Lifetime of a Struts Action
I start with that, because that might already solve your issue.
👉 A new instance of a Struts action is created for each request.
That means for you when connect the attributes list (left side) and doubleList (right side) to fields in a class derived from ActionSupport - like in the example OptionTransferSelectAction above - you must ensure, that you initialize it with meaningful values, I mean values that reflect the current state you want to show to the user. In the worst case you have to fetch the values from the database with each request.
Alternatively you can inject a bean into the action with a dedicated lifetime (e.g. session scoped). I might line that out in a separate post.
(BTW I would be thankful if someone else could provide further information, if the lifetime of a Struts action can be changed directly).
How optiontransferselect works
This tag wraps up two select tags (or more specifically updownselect tags). I will line out the function of it first, because it makes us better understand optiontransferselect. (Sidenote: Contrary to JSF, Struts clearly distinguishes between attributes for get and set operations.)
To connect the select tag with the underlying data, these are the three relevant attributes:
list - This is the list of all available values (=get).
value - This is the list of values initially selected (=get).
name - The name of the property (field) of the action where the selected values will be supplied on form submit (=set).
So the only property your action will recieve is the one connected with name. The select tag will NOT...
...post back the complete list of values (the value of list) to the action.
...change the values of list and value in the underlying Java class / action.
And the same is true for optiontransferselect. Which makes the semantics quite weird, because some changes (namely which values show up left and which show up right) will never be post back to the Struts action, you only can get hold of the selected values of both sides.
The major difference is that you have those three attributes now twice:
list --> list for the left and doubleList for the right side.
value --> value for the left and doubleValue for the right side.
name --> name for the left and doubleName for the right side.
The question now is how to come by that you will only get the selected values? I would suggest to automatically select them right before submission:
<s:submit value="Save" onclick="selectAllOptions(document.getElementById('idLeft'));selectAllOptions(document.getElementById('idRight'));"/>
Where idLeft corresponds to the value of id in the optiontransferselect and idRight corresponds to the value of doubleId. With that change you would get the complete list of left and right values in name and doubleName respectively.
The code is exactly the same as for the button you would get with allowSelectAll="true" and the JavaScript method selectAllOptions is provided by Struts via the optiontransferselect.js, regardless of allowSelectAll was true or false.
Related
When I press 4,5,6 seriatim, its writing 654 cause the line is always staying same place. I'm using Java & Wicket.
This part is in java class:
koordinasyonId.add(new OnChangeAjaxBehavior() {
private static final long serialVersionUID = 3097782061837606985L;
#Override
protected void onUpdate(AjaxRequestTarget target) {
if(koordinasyonId.getModelObject()!=null){
String koordinasyonIdValue = koordinasyonId.getModelObject();
String kordinasyonValue ="";
for(int i=0;i<koordinasyonIdValue.length();i++) {
String regex = "^[0-9]{1,2}([,.][0-9]{1,2})?$";
if (Pattern.matches(regex,koordinasyonIdValue.charAt(i)+"")) {
kordinasyonValue = kordinasyonValue + koordinasyonIdValue.charAt(i);
}else if(".".equals(koordinasyonIdValue.charAt(i)+"") || ",".equals(koordinasyonIdValue.charAt(i)+"")){
kordinasyonValue = kordinasyonValue + koordinasyonIdValue.charAt(i);
}
}
koordinasyonId.setModelObject(kordinasyonValue);
target.add(koordinasyonId);
}
}
});
This part is in html file: (Actually javascript can add to code. So I used in this part)
<script type="text/javascript">
$("#koordinasyonId").change(function(){
let koordinasyonId = document.getElementById("koordinasyonId").value;
let kordinasyonValue;
if(koordinasyonId !=null){
for(var i=0;i<koordinasyonId.length;i++) {
if (!isNaN(koordinasyonId.charAt(i))) {
kordinasyonValue +=koordinasyonId.charAt(i);
} else {
if (koordinasyonId.charAt(i).match(".") ||koordinasyonId.charAt(i).match(",") ) {
kordinasyonValue +=koordinasyonId.charAt(i);
}
}
}
}
document.getElementById("koordinasyonId").value=koordinasyonValue;
});
</script>
Using OnChangeAjaxBehavior on a TextField without any validators and updating the TextField via Ajax in the onUpdate method will lead to that behaviour.
The OnChangeAjaxBehavior on a TextField works as follows:
After the user entered something into the TextField the Behaviour will do an Ajax Request to the server with that input and ask it to validate that input.
If it is valid it will then call the onUpdate method, otherwise it will call the onError method.
So in your case this will lead to the following:
You type 4 into the TextField
Wicket will do an Ajax Request and validate if 4 is a valid input
As it is a valid input it will call your onUpdate method
Inside the onUpdate method you tell wicket to do an ajax refresh on the Input/TextField
Because of that Ajax update the curser inside the Input/TextField is reset to the first position
The Solution is most likely that OnChangeAjaxBehavior is not the correct way to do whatever you are trying to do. OnChangeAjaxBehavior works great for TextFields that have a strict validation, like for example an Input for an IBAN where you can determine the moment the user is done with inputting with certainty because the valid inputs have a fixed length.
If you would tell us what exactly you are trying to archieve here we could probably point you in the right direction of how to archieve that with wicket:
Are you trying to validate the input?
Are you trying to prevent the user from entering certain values inside the input/TextField?
I have built a number of custom server controls and routinely call javascript functions that are embedded into my controls. But I haven't been able to figure out how to create a property that the user of the control can add their own function to and their javascript function in the page containing the control will be called. I need to do something like OnClientClick for an asp:Button control.
Edit 1:
Thanks to the answer by #h2015 I have made progress on this.
In my control I create a public property for the user's script,
public string EditAddressScript
{
set
{
string scriptName = "EditAddressScript";
Type csType = this.GetType();
ClientScriptManager csm = Page.ClientScript;
string scriptText = string.Format("function EditAddress() {{{0}}}", value);
csm.RegisterClientScriptBlock(csType, scriptName, scriptText, true);
}
}
Then in the RenderContents section of my control I check whether a value has been specified for EditAddressScript and create a button if it has.
output.Write("<input id='btnEdit' type='button' value='Edit Address' style='font-size: 6pt;' onclick='EditAddress();' />");
The page that uses this control creates it dynamically so I do something like this,
ECFControls.DefendantAddressReview defendantAddress = new ECFControls.DefendantAddressReview();
divControls.Controls.Add(defendantAddress);
defendantAddress.ClientEditAddressScript = "alert('Hello, World');";
This works, but is far from optimal.
I would like to define the script in the aspx page and then just give my control the name of the script, rather than setting the value of EditAddressScript to the actual javascript code.
In the RenderContents section of the control I have the name of the script hardcoded I would like that to be dynamic.
Edit 2:
Okay, it looks like I was making this far more complicated than necessary. All that is needed is to create a script in the parent aspx page and set the event in the control to that script.
So this is what I have now
Add script to aspx page.
function EditAddress() {
alert("Hello, World");
}
Create a property in the control to hold the value (_EditAddressScript is a private string variable in the control)
public string EditAddressScript
{
set
{
_EditAddressScript = value;
}
}
Then in the RenderContents section of the control I check whether a value has been specified for EditAddressScript and create a button if it has.
if(_EditAddressScript.Trim() != "")
output.Write(string.Format("<input id='btnEdit' type='button' value='Edit' style='font-size: 6pt;' onclick='{0}' />", _EditAddressScript));
Create the control like this,
ECFControls.DefendantAddressReview defendantAddress = new ECFControls.DefendantAddressReview();
divControls.Controls.Add(defendantAddress);
defendantAddress.EditAddressScript = "EditAddress()";
If the control were created declaratively I could do this,
<ECF:DefendantAddressReview ID="defendantAddressReview" runat="server" EditAddressScript="EditAddress()" />
Is there a better approach?
Thanks.
this.Page.ClientScript.Register...
https://msdn.microsoft.com/en-us/library/ms178207.aspx
I explored two possible solutions in the edits to my original question. The second edit achieves the desired result. I wanted to have an optional property for a custom ASP.Net server control that would specify the name of a javascript function that the user of the control could place in the same page as the control. Here's how I did it.
Add a public string property to the server control that defines the name of your javascript function. (_CustomJavascript is a private string variable in the control)
public string CustomJavascript
{
set
{
_CustomJavascript = value;
}
}
Then in the RenderContents section of the control check whether a value has been specified for _CustomJavascript and add the code to call that javascript if it has been. In my case I was creating a composite control and wanted an edit button to display that would call the user's javascript function.
if(_CustomJavascript.Trim() != "")
output.Write(string.Format("<input id='btnEdit' type='button' value='Edit' style='font-size: 6pt;' onclick='{0}' />", _CustomJavascript));
All the user has to do is write their function.
function EditAddress() {
alert("Hello, World");
}
And give the name of their function to the CustomJavascript property when declaring the control.
<cc:AddressReview ID="addressReview" runat="server" CustomJavascript="EditAddress()" />
UPDATED : The idea is simple : I want to populate an input field with a default value for ImageTitle field of my model. The value come from the database. This default value should be the Filename (also stored in db). The user has the option to leave it as it is or change it before the page is POSTed.
I have a view that renders a form with html helpers like #EditorFor. Once the page is loaded ($(document).ready()) I tried to use JQuery to set the value of an editable input with the id label-title but it turned out that when I was posting the page I got an exception. This exception is not present if I enter manually an imagetitle in the input.
I tried to assign ImageTitle a value in the GET edit action method. myImage.ImageTitle = myImage.Filename
Like it did with JQuery, the input is populated properly with a the value but when I POST the page, same exception occurs.
An exception of type 'System.InvalidOperationException' occurred in System.Web.Mvc.dll but was not handled in user code Additional information: There is no ViewData item of type 'IEnumerable' that has the key 'UseType'. Exception thrown: 'System.Data.Entity.Validation.DbEntityValidationException' in EntityFramework.dll Exception thrown: 'System.InvalidOperationException' in System.Web.Mvc.dll This exception seems to be unrelated to my real problem, since I don't get it if I remove the single line myImage.ImageTitle = myImage.Filename and the app function perfectly.
Here is some code that I use.
#Html.EditorFor(model => model.ImageTitle, new { htmlAttributes = new { id = "label-title", #class = "form-control" } })
generates this html
<input class="form-control text-box single-line valid" id="label-title" name="ImageTitle" value="benq160715074510.jpg" type="text"></input>
I don't get any error when I enter manually a value for ImageTitle but everything I've tried with either JQuery, Javascript or assigning a value in controller action trigger an exception.
My edit method is pretty standard
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "All my fields here including ImageTitle..")] TutoringImage tutoringImage)
{
if (ModelState.IsValid)
{
Db.Entry(Image).State = EntityState.Modified;
Db.SaveChanges();
return RedirectToAction("Index");
}
return View(Image);
}
Can anyone help on that one?
I think you should not use the attr function in this code $('#label-title').attr('value', imgTitle);.
The correct way to fill up a input value is with the value function. $('#label-title').val(imgTitle);
Here is the solution that worked in the end.
My form called an action method called Save() in which I was creating a new TutoringImage object. When I assigned the value on this first occurence of the object, it worked. When redirected to Edit(int? id) action, I could leave the field ImageTitle as is or change it without any bug, entry was saved correctly in the db.
What I was trying before that was to populate this field after its creation, first with javascript on the client and the in my controller in the Edit(int? id) GET action like this :
if (tutoringImage.ImageTitle == null)
{
var query = from db in Db.TutoringImage
where db.ImageID == tutoringImage.ImageID
select db;
foreach (TutoringImage image in query)
{
image.ImageTitle = tutoringImage.Filename;
}
}
try
{
if (ModelState.IsValid)
{
Db.Entry(tutoringImage).State = EntityState.Modified;
Db.SaveChanges();
}
}
This failed poorly and I can't explain why. What worked was to assign the "default" value that I wanted on object creation and not after... Simply added a line of code in my object creation in the action method that followed the drag and drop form.
TutoringImage im = new TutoringImage
{
Filename = fileName,
// and so on
ImageTitle = file.FileName,
};
I've look an found only a similar post and didn't really answer my question or maybe they did but I didn't understand. The post I read was this one: Why does this javascript variable I'm creating via C# only get updated once?
I'm using a paged gridview and every time it's object data source runs the SelectCountMethod, I use the returning value on javascript. But, I've noticed that even thought that same returned value changes, on the server side. On javascript this value doesn't update.
My program is quite long but I'll use a basic example and hopefully some of you will understand it.
Client side:
function SomeFuntion()
{
alert("<%=num%>");
}
Server side:
//Global variable
Public Static int num = 0;
Public int SelectCountMethod()
{
var num = SomeMethod(); //Returns int
return num;
}
For example, on the server side num returns 60 and then this value updates to 7. On the server side num equals 7 but on the client side it's still 60. Is there a way to update the client sides value?
I apologies for my poor typing skills, English is not my native language.
Some examples might be helpful and thanks in advance.
I noticed that it doesn't mater where I update this variable(on selectCount method or any other method), on the client side doesn't update.
Taking a look at your client-side code, the "<%=num%>" is actually run on the server. If you examined the source in your browser, what you'll see is:
function SomeFuntion()
{
alert("60");
}
As you can see--there is no variable to update. In order to see that "60" change to "7", you'd have to refresh the client to pick up the new value that the server has for "num".
You could modify your JS method like this
var myMsg = <%=num%>;
function SomeFuntion()
{
alert(myMsg);
}
and in the codebehind
public int num = 60;
public int SelectCountMethod()
{
num = SomeMethod(); //Returns int
ScriptManager.RegisterStartupScript(this,
this.GetType(),
"Funct",
"myMsg = " + num + ";",
true);
return num;
}
So every time your method SelectCountMethod() is called, your JS variable myMsg get a new value because of the line ScriptManager.RegisterStartupScript
Without your server side code, we won't be able to find the ideal solution. However, you could potentially do the following:
Use a Hidden Field to store the value.
Use a global variable for the page, to pass the value to global variable in your JavaScript.
The easiest would be the Hidden Field, the reason is you can easily modify the data on both Client and Server without any real issues. You'll want to ensure that you do not modify the state to often.
<input type="hidden" id="hdTimer" runat="server" />
Then you can do your JavaScript, such as:
$('#Example').on('change', function () {
$('#hdTimer').val('60');
});
Now throughout the Client code you'll be able to modify the field with no issues, but when you need to submit a form, for a PostBack. You can use the field server side:
var content = hdTimer.value;
As I noted though, excessive cross manipulation may cause an issue at some point. Depending on the complexity. Your other approach would be the Global.
// Server Side
var example = 60;
protected void Page_Load(object sender, EventArgs e)
{
}
So this Global will hold the value, but when you reinitialize the value at Page Load it will hold be able to push an updated value to your JavaScript:
//Client Side:
var example = '<%= example %>';
The key though, will be to ensure you properly reinitialize the value.
When you do a PostBack your page is reinitialized, which can modify values on you if you aren't aware. This is incredibly important.
Use an HttpHandler and jQuery. Google is your friend, there are several examples on SO as well.
I found a possible solution, inefficient, but it will have to do. I have a search textbox that every time the search button is clicked, updates the grid view with the retrieved data from a data base. When the Onclick is called it binds the data source with the gridView. What I did was call the SelectCountMethod again right below the binding and used the same parameters I had stored on the Object data source as paramaters for the selectCountMethod. Then the amount returned by the selectCount I stored it on a hiddenField and that's it.
//Global variables
string _param1 = string.Empty,
_param2 = string.Empty;
//On click method for search btn
protected void OnSearch(object sender, EventArgs e)
{
gv.DataBind();
someHiddenField = SelectCountMethod(param1, param2);
}
protected void OnSelecting(object sender, ObjectDataSourceSelectingEventArgs e)
{
try
{
e.InputParameters["Param1"] = param1;
_param1 = param1
e.InputParameters["Param2"] = param2;
_param2 = param2;
}
catch (Exception ex)
{
cvServerError.IsValid = false;
cvServerError.ErrorMessage = ex.Message;
}
}
We currently have a form with the standard multi-select functionality of "here are the available options, here are the selected options, here are some buttons to move stuff back and forth." However, the client now wants the ability to not just select certain items, but to also categorize them. For example, given a list of books, they want to not just select the ones they own, but also the ones they've read, the ones they would like to read, and the ones they've heard about. (All examples fictional.) Thankfully, a selected item can only be in one category at a time.
I can find many examples of moving items between listboxes, but not a single one for moving items between multiple listboxes. To add to the complication, the form needs to have two sets of list+categories, e.g. a list of movies that need to be categorized in addition to the aforementioned books.
EDIT: Having now actually sat down to try to code the non-javascripty bits, I need to revise my question, because I realized that multiple select lists won't really work from the "how do I inform the server about all this lovely new information" standpoint. So the html code is now a pseudo-listbox, i.e. an unordered list (<ul>) displayed in a box with a scrollbar, and each list item (<li>) has a set of five radio buttons (unselected/own/read/like/heard).
My task is still roughly the same: how to take this one list and make it easy to categorize the items, in such a way that the user can tell at a glance what is in what category. (The pseudo-listbox has some of the same disadvantages as a multi-select listbox, namely it's hard to tell what's selected if the list is long enough to scroll.) The dream solution would be a drag-and-drop type thing, but at this point even buttons would be OK.
Another modification (a good one) is that the client has revised the lists, so the longest is now "only" 62 items long (instead of the many hundreds they had before). The categories will still mostly contain zero, one, or two selected items, possibly a couple more if the user was overzealous.
As far as OS and stuff, the site is in classic asp (quit snickering!), the server-side code is VBScript, and so far we've avoided the various Javascript libraries by the simple expedient of almost never using client-side scripting. This one form for this one client is currently the big exception. Give 'em an inch and they want a mile...
Oh, and I have to add: I suck at Javascript, or really at any C-descendant language. Curly braces give me hives. I'd really, really like something I can just copy & paste into my page, maybe tweak some variable names, and never look at it again. A girl can dream, can't she? :)
[existing code deleted because it's largely irrelevant.]
Funny, I also, just yesterday googled "moving items between multiple listboxes" and your question pop up.
I didnt read your entire post so Im not sure if I can help out.
But this solved my problem.
I downloaded this solution.
And then made the following changes...
Add one extra hidenfield in the html
per (extra) listbox.
Modified like below, you can
compare what changes I made...
//...
public partial class ErrorActions : System.Web.UI.Page
{
private XmlDocument _xmlDocument = new XmlDocument();
public ListBox FromListBox
{
get
{
return lstFrom;
}
}
public ListBox AbortListBox
{
get
{
return lstToAbort;
}
}
public ListBox ClearingListBox
{
get
{
return lstToClearing;
}
}
protected void Page_Load(object sender, EventArgs e)
{
Page.ClientScript.RegisterClientScriptInclude("listboxjs", "/JavaScripts/listbox.js");
if (!IsPostBack)
{
string movejs = "move('{0}','{1}','{2}')";
string unselectjs = "unselect('{0}')";
lstFrom.Attributes["onclick"] = String.Format(unselectjs, lstToAbort.ClientID);
lstFrom.Attributes["onclick"] = String.Format(unselectjs, lstToClearing.ClientID);
lstToAbort.Attributes["onclick"] = String.Format(unselectjs, lstFrom.ClientID);
lstToAbort.Attributes["onclick"] = String.Format(unselectjs, lstToClearing.ClientID);
lstToClearing.Attributes["onclick"] = String.Format(unselectjs, lstFrom.ClientID);
lstToClearing.Attributes["onclick"] = String.Format(unselectjs, lstToAbort.ClientID);
btnToAbort.Attributes["onclick"] = String.Format(movejs, lstFrom.ClientID, lstToAbort.ClientID, hdnDropdownsAbort.ClientID);
btnFromAbort.Attributes["onclick"] = String.Format(movejs, lstToAbort.ClientID, lstFrom.ClientID, hdnDropdownsAbort.ClientID);
btnToClearing.Attributes["onclick"] = String.Format(movejs, lstFrom.ClientID, lstToClearing.ClientID, hdnDropdownsClearing.ClientID);
btnFromClearing.Attributes["onclick"] = String.Format(movejs, lstToClearing.ClientID, lstFrom.ClientID, hdnDropdownsClearing.ClientID);
}
else
{
//if (!(String.IsNullOrEmpty(hdnDropdowns.Value)))
//{
// PopulateListBoxes();
//}
if (!(String.IsNullOrEmpty(hdnDropdownsAbort.Value)))
{
PopulateAbortListBox();
}
if (!(String.IsNullOrEmpty(hdnDropdownsClearing.Value)))
{
PopulateClearingListBox();
}
}
}
private void PopulateListBox(ListBox listBox)
{
listBox.Items.Clear();
XmlNodeList nodes = _xmlDocument.SelectNodes("listboxes/" + listBox.ClientID + "/option");
foreach (XmlNode node in nodes)
{
listBox.Items.Add(new ListItem(node["key"].InnerText, node["value"].InnerText));
}
}
//private void PopulateListBoxes()
//{
// _xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdownsAbort.Value));
// //PopulateListBox(lstFrom);
// PopulateListBox(lstToAbort);
// PopulateListBox(lstToClearing);
//}
private void PopulateAbortListBox()
{
_xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdownsAbort.Value));
PopulateListBox(lstToAbort);
}
private void PopulateClearingListBox()
{
_xmlDocument.LoadXml(HttpUtility.UrlDecode(hdnDropdownsClearing.Value));
PopulateListBox(lstToClearing);
}
protected void btnDoIt_Click(object sender, EventArgs e)
{
MissionErrorCodeDB db = new MissionErrorCodeDB();
db.DeleteErrorCodeActions(ErrorAction.AbortMission);
db.DeleteErrorCodeActions(ErrorAction.GoToClearingStation);
foreach (ListItem item in lstToAbort.Items)
{
db.AddErrorCodeAction(Convert.ToInt32(item.Value), ErrorAction.AbortMission);
}
foreach (ListItem item in lstToClearing.Items)
{
db.AddErrorCodeAction(Convert.ToInt32(item.Value), ErrorAction.GoToClearingStation);
}
}
protected override void OnPreRender(EventArgs e)
{
MissionErrorCodeDB db = new MissionErrorCodeDB();
List<MissionErrorCode> aborts = db.GetAll(ErrorAction.AbortMission);
List<MissionErrorCode> clearing = db.GetAll(ErrorAction.GoToClearingStation);
List<MissionErrorCode> all = db.GetAll();
all.RemoveAll(delegate(MissionErrorCode mec)
{
foreach (MissionErrorCode item in aborts)
{
if( mec.ErrorCode == item.ErrorCode )
return true;
}
return false;
});
all.RemoveAll(delegate(MissionErrorCode mec)
{
foreach (MissionErrorCode item in clearing)
{
if (mec.ErrorCode == item.ErrorCode)
return true;
}
return false;
});
populateBoxFromDatabase(AbortListBox, aborts);
populateBoxFromDatabase(ClearingListBox, clearing);
populateBoxFromDatabase(FromListBox, all);
base.OnPreRender(e);
}
private void populateBoxFromDatabase(ListBox listBox, List<MissionErrorCode> errorCodes)
{
string text;
int textLength = 46;
listBox.Items.Clear();
foreach (MissionErrorCode item in errorCodes)
{
if (item.ErrorText.Length < textLength)
{
text = item.ErrorCode + " - " + item.ErrorText;
}
else
{
text = item.ErrorCode + " - " + item.ErrorText.Substring(0, textLength - 1) + "...";
}
listBox.Items.Add(new ListItem(text, item.ErrorCode.ToString()));
}
}
}
//...
To avoid big chunks of Javascript I suggest you to do the work with a couple a Ajax calls
Add several buttons next to the item (Already have it, Want it, etc). Each button should call a page in the server that sets the item to the correct category.
In the success callback, call other ajax function that refresh only the category list affected.
Use jQuery and you will see that making the calls are pretty simple.
Good luck.
Well, nobody seems to want to do my work for me, so here's what we ended up doing. (It's not entirely done yet; when it is, I might post the code just for completeness' sake.)
We've taken the plunge and downloaded JQuery, specifically the JQuery UI "Sortable" functions. Like I said, the main dropdown is now a pseudo-listbox, i.e. a ul with restricted height and overflow:auto. Each item has five radio buttons next to it, which are hidden with Javascript. (That is, if Javascript isn't available, the user just sees a list with radio buttons.) When you drag items from the main list into the (script-generated) category lists, the appropriate radio button is marked. There will also be some code that runs on page load to move already-marked options from the main list to the appropriate category (i.e. for editing capability).