...

View Full Version : Multi-Select Picklist Not Saving



jaspla
06-22-2012, 08:39 PM
I copied some code to create a multi-select picklist out of an option set in Dynamics CRM. Basically, I have a drop-down list and this script turns into an element with multiple checkbox options. When the form loads, the checkboxes form. When the user saves the form, it stores the selected choices in a text box that's hidden from the user.

The problem I'm having is that when a user only selects one option and saves, upon re-loading the form the checkboxes are blank (the one option that was selected is blank). Also, when they select all options and save, one option is unechecked upon reloading. Is there a way so that if they save with one option or all options checked, that the form reloads showing the appropriate selections?



function OpportunityOnLoad ()
{
// PL - the picklist attribute; PLV - used to save selected picklist values
var PL = crmForm.all.new_reasons; //CREATE NEW PICKLIST
var PLV = crmForm.all.new_reasonstext; //CREATE NEW TEXT FIELD TO STORE STRING


PL.style.display = "none"; //HIDES THE CONTROL
PLV.style.display = "none"; //HIDES THE CONTROL


// Create a DIV container
var addDiv = document.createElement("<div style='overflow-y:auto; height:135px; width:278px; border:1px #a1a5aa solid; background-color:#ffffff;' />");
PL.parentNode.appendChild(addDiv);
// Initialise checkbox controls


for( var i = 1; i < PL.options.length; i++ )
{
var pOption = PL.options[i];
if( !IsChecked( pOption.text ) )
var addInput = document.createElement("<input type='checkbox' onclick='CallOnChangeEvent()' style='border:none; width:25px; align:left;' />" );
else
var addInput = document.createElement("<input type='checkbox' onclick='CallOnChangeEvent1()' checked='checked' style='border:none; width:25px; align:left;' />" );
var addLabel = document.createElement( "<label />");
addLabel.innerText = pOption.text;


var addBr = document.createElement( "<br>"); //it's a 'br' flag


PL.nextSibling.appendChild(addInput);
PL.nextSibling.appendChild(addLabel);
PL.nextSibling.appendChild(addBr);
}


// Check if it is selected
function IsChecked( pText )
{
if(PLV.value != "")
{
var PLVT = PLV.value.split(", ");
for( var i = 0; i < PLVT.length; i++ )
{
if( PLVT[i] == pText )
return true;
}
}
return false;
}
}


function CallOnChangeEvent()
{
var PL = crmForm.all.new_reasons;
var PLV = crmForm.all.new_reasonstext;
PLV.value = "";
var getInput = PL.nextSibling.getElementsByTagName("input");
for( var i = 0; i < getInput.length; i++ )
{
if( getInput[i].checked)
{
PLV.value += getInput[i].nextSibling.innerText + ", ";
}
}


//MUST DO THIS TO TRIGGER A SAVE EVENT
var Name = Xrm.Page.data.entity.attributes.get("new_reasonstext");
Name.setValue(PLV.value);
}

Old Pedant
06-22-2012, 08:44 PM
Don't know how we could guess what the problem is without seeing how the selected check boxes are saved and how the <select> is then created upon re-load.

And you don't even show the code for the IsChecked function.

In any case, this seems to me like a silly way to do this. Why not change the server-side code to create the checkboxes directly, instead of the <select>???

Old Pedant
06-22-2012, 08:46 PM
And the other part of the code that is silly, to me, is that you call the CallOnChangeEvent function on each checkbox change. Why not just call it once, when the <form> is submitted?

jaspla
06-22-2012, 08:59 PM
Don't know how we could guess what the problem is without seeing how the selected check boxes are saved and how the <select> is then created upon re-load.

And you don't even show the code for the IsChecked function.

In any case, this seems to me like a silly way to do this. Why not change the server-side code to create the checkboxes directly, instead of the <select>???I should've mentioned it's the online version of MS Dynamics CRM, so I can't access server code. The IsChecked is on there.

Old Pedant
06-22-2012, 09:18 PM
Okay, but we would still need to see what the <select> that is produced looks like.

Oh...and I would think that the better way to do this would be to HIDE the <select> and then, when the <form> is submitted, you simply go back to the <select> and add SELECTED to the <option>s that correspond to the checked checkboxes!

And this code makes no sense, given the comment attached to it:


var PLV = crmForm.all.new_reasonstext; //CREATE NEW TEXT FIELD TO STORE STRING

That doesn't "CREATE" one darned thing. Unless that field already exists, your PLV variable is simply going to be NULL, so of course nothing after that works.

And, not so incidentally, this code will ONLY work in MSIE. "all" is only supported by MSIE. (Well, and some versions of Opera, I have heard.)

Old Pedant
06-22-2012, 09:53 PM
The more I look at that code, the dumber it looks. What a ridiculous way to find out if a given <option> is selected!

Try this much simpler code. That, not so incidentally, works in FF and Chrome, which your code wouldn't come close to doing.


<html>
<body>
<form name="crmForm">
<div>
<select name="new_reasons" multiple size="7">
<option>choose one or more</option>
<option>Bad Breath</option>
<option selected>Body Odor</option>
<option selected>Too Dumb</option>
<option>Too Smart</option>
</select>
</div>
<hr/>
<input type="submit"/>
</form>

<script type="text/javascript">
function OpportunityOnLoad ()
{
// I assume you have a form named "crmForm"
var form = document.crmForm;

// *OR* if the <form> has an ID of "crmForm" instead, use:
// var form = document.getElementById("crmForm");

// and I assume you have a <select name="new_reasons" multiple>
var PL = form.new_reasons;


// to see this work, do *NOT* hide the <select>
// so UN-comment next line after you are satisified that it works
// PL.style.display = "none"; // hide the <select>


// Create a DIV container
var addDiv = document.createElement("div");
addDiv.style.overflowY = "auto";
addDiv.style.height = "135px";
addDiv.style.width = "278px";
addDiv.border = "solid 1px #a1a5aa"
addDiv.backgroundColor = "white";

PL.parentNode.appendChild(addDiv);

// Initialise checkbox controls
for( var i = 1; i < PL.options.length; i++ )
{
var pOption = PL.options[i];
var cb = document.createElement("input");
cb.type = "checkbox";
cb.style.border = "none";
cb.width = "25px";
cb.align = "left";
cb.id = "ZZZCB_" + i;
cb.checked = pOption.selected;
cb.onclick = function() {
var sel = this.form.new_reasons;
var optnum = Number(this.id.replace("ZZZCB_",""));
sel.options[optnum].selected = this.checked;
}
var addLabel = document.createElement( "label");
addLabel.for = "ZZZCB_" + i;
addLabel.innerHTML = pOption.text;

var addBr = document.createElement("br");
addDiv.appendChild(cb);
addDiv.appendChild(addLabel);
addDiv.appendChild(addBr);
}


}
OpportunityOnLoad();
</script>
</body>
</html>

Old Pedant
06-22-2012, 10:02 PM
Hmmm...I don't see why, but putting in the
addLabel.for = "ZZZCB_" + i;
didn't cause the <label>s to act as true labels for the checkboxes.

Okay, so let's hack it: Add an onclick method to the labels as well.


var addLabel = document.createElement( "label");
addLabel.for = "ZZZCB_" + i;
addLabel.innerHTML = pOption.text;
addLabel.onclick = function() {
document.getElementById(this.for).click();
}


Now the labels work as you would want them to.

Old Pedant
06-22-2012, 10:17 PM
*** SIGH ***

It figures. Now there is code in there that make MSIE barf! Even MSIE 9, which is *supposed* to be compatible!

Okay...*NOW* this code works in MSIE 9, FF, and Chrome. You'll have to check it in MSIE 8 and below.



<html>
<body>
<form name="crmForm">
<div>
<select name="new_reasons" multiple size="7">
<option>choose one or more</option>
<option>Bad Breath</option>
<option selected>Body Odor</option>
<option selected>Too Dumb</option>
<option>Too Smart</option>
</select>
</div>
<hr/>
<input type="submit"/>
</form>

<script type="text/javascript">
function OpportunityOnLoad ()
{
// I assume you have a form named "crmForm"
var form = document.crmForm;

// *OR* if the <form> has an ID of "crmForm" instead, use:
// var form = document.getElementById("crmForm");

// and I assume you have a <select name="new_reasons" multiple>
var PL = form.new_reasons;


// to see this work, do *NOT* hide the <select>
// so UN-comment next line after you are satisified that it works
// PL.style.display = "none"; // hide the <select>


// Create a DIV container
var addDiv = document.createElement("div");
addDiv.style.overflowY = "auto";
addDiv.style.height = "135px";
addDiv.style.width = "278px";
addDiv.border = "solid 1px #a1a5aa"
addDiv.backgroundColor = "white";

PL.parentNode.appendChild(addDiv);

// Initialise checkbox controls
for( var i = 1; i < PL.options.length; i++ )
{
var pOption = PL.options[i];

var cb;
try {
// the idiotic MSIE way:
cb = document.createElement(
'<input type="checkbox" ' + ( pOption.selected ? "checked/>" : "/>")
);
} catch( e ) {
// the right way:
cb = document.createElement("input");
cb.type = "checkbox";
cb.checked = pOption.selected;
}
cb.style.border = "none";
cb.width = "25px";
cb.align = "left";
cb.id = "ZZZCB_" + i;
cb.onclick = function() {
var sel = this.form.new_reasons;
var optnum = Number(this.id.replace("ZZZCB_",""));
sel.options[optnum].selected = this.checked;
}
var addLabel = document.createElement( "label");
addLabel.id = "ZZZZCB_" + i; // notice the one extra "Z" (sneaky, no?)
addLabel.innerHTML = pOption.text;
addLabel.onclick = function() {
document.getElementById(this.id.substring(1)).click();
}

var addBr = document.createElement("br");
addDiv.appendChild(cb);
addDiv.appendChild(addLabel);
addDiv.appendChild(addBr);
}


}
OpportunityOnLoad();
</script>
</body>
</html>

Old Pedant
06-22-2012, 10:19 PM
See, the best part about doing it this way is that the <select multiple> is still what is sent back to the server, so it can't even tell you have done anything!



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum