Add to List if not in Drop Down

Sep 28, 2010 at 11:18 PM

Hi there,

Has anyone worked a solution that would add items to a list if the user enters into lookup drop down an item that doesn't exist?

TIA,

Josh

Coordinator
Sep 28, 2010 at 11:45 PM
Josh: Interesting idea. Typically a dropdown doesn't allow for value additions, though. Can you explain more what you're looking for? This might be a good addition to SPServices. M.
Sep 29, 2010 at 12:29 AM

I find the need for dropdowns both ways.  Some are restricted to items in the list for relationships and such.  While others are for options that warrant user control of new items. 

For example, I have systems that do quotations for advertizing print orders.  There are an unlimited number of paper types and sizes possible.  It is unrealistic to attempt to populate the list with every option.  Do your best and there will still be something new tomorrow.  The client requirements are such that they want to add items on-the-fly.  I'm sure this is true for any number of business scenerios.

The solution would be to catch the new entry, prompt for 'New Item?', then use webservices via spservices to add the item to source list and requery the drop down (with an optional step of visiting NewItem.aspx for entering related details).

I gather from your response that no one is doing this to your knowledge...I do it all the time in vb, but wouldn't know how to get started with it here.

Josh

 

Coordinator
Sep 29, 2010 at 12:40 AM

There are several approaches you can take with SharePoint on this. If you just want users to be able to add their own one-off values (which sounds like it might be the best approach in the scenario you describe) you can simply enable 'Allow 'Fill-in' choices: '. If you want the user to be able to add permanent values to the reference list, you can use the $().SPServices.SPLookupAddNew function.

The trick with the 'optional step of visiting NewItem.aspx for entering related details' option is how to get the user there without saving the partially completed item they are working with and then back.

M.

Sep 29, 2010 at 12:54 AM

Allow Fill-In Choices, is that spservices option or MOSS?  I don't see it in WSS.  I will look into SPLookupAddNew.

I'm not a web dev so I don't think about the page life stuff naturally. 

I suppose one could try script that sets every value on the page from querystrings then goto to LookupList\NewItem.aspx with all those values in the &source querystring.  Then when the LookupList\newitem.aspx posts, it will redirect to the source page with values populated from querystring.

Makes sense to me, but will it work(?)

Thanks again.

Josh

Coordinator
Sep 29, 2010 at 1:00 AM

'Allow 'Fill-in' choices:' is available in WSS *and* MOSS. It's one of the options when you create a Choice column.

The Query String idea isn't a bad one, but there are lots of conditions where it wouldn't work. For instance, where you have Multiline text columns in your list or multi-select Choice columns where many choices are selected. There have always seemed to be so many conditions where any approach *wouldn't* work that I haven't gone any further with the idea, even though I think it'd be awesome to offer it as an option.

The most viable approach that I have thought of is to pop up a modal form to capture the new reference item, refreshing the existing value options on save. Even that can get pretty tricky, depending on the complexity of the lists involved.

M.

Sep 29, 2010 at 2:27 AM
Edited Sep 29, 2010 at 3:40 AM

But can you populate a choice column from list like the lookup column?  I only use  choice when a handful of static options are needed.  Allowing Fill-In for lookup columns would be a great feature!

 

Thanks again.

Josh

 

 
Coordinator
Sep 29, 2010 at 2:31 AM

Sorry; you're right. Choice columns have the "Allow 'Fill-in' choices" option, but Lookup columns do not. Take a look at SPLookupAddNew and see if it helps, with the caveats above.

M.

Sep 29, 2010 at 8:57 PM

Marc,

Okay so I like the SPLookupAddNew it's easier than going out to the list manually then coming back to edit.  But i'd still like not to lose my work on the new item.

I started thinking about using query strings like we discussed above because my form is simple and I think I don't have things that would complicate that method.  Then I notice your SPRedirectWithID thought of something else.  What if I save the partialy filled item then come back to it on EditForm.aspx

Assuming the columns where SPLookupAddNew is used are not required and...would it be possible to force the NewItem.apsx to save the item upon clicking the AddNewLink.  Then alter the link to include the ID in the source using  $().SPServices.SPGetLastItemId. (?)

Similar to SPRedirectWithID, but different, I think.  Can you point me to an example of how to use completefunc: to alter the AddNewLink?

Thanks,

Josh

Coordinator
Sep 30, 2010 at 3:58 AM
This approach seems viable, but it'll be tricky. At the very least, the 'Title' column will be required. SPRedirectWithID was probably the hardest function to get running in the library to date, so be forewarned! The problem with triggering the click event on the OK button is that it causes a postback to save the item. At that point, you'll have lost control of the page. You'd have to override that behavior and write the item yourself, probably with the Web Services. More trickiness! In the long run, you may be causing more work for yourself than you'll get back in benefits. M.
Jun 24, 2011 at 4:59 PM
Edited Jun 24, 2011 at 5:01 PM

Hi Marc,

It's been a wile since this post, but curious if you've tried using the new modal dialogs in SP2010 to overcome this problem.  My understanding is the new modal dialogs are actually rendering other forms in the same page as opposed to a popup which open a new browser window.

TIA,

Josh

Coordinator
Jun 25, 2011 at 8:05 PM

No, I haven't done anything further with it.

Yes, the "modal" dialogs are simply rendering the other form in an iframe nestled in a div, if I recall.

M.

Jun 27, 2012 at 7:46 PM

I got this working outside of SPServices. I have a library called invoices with a lookup on a list called IT Vendors. I modified the advances settings of Invoices to Not launch forms in a dialog. Then on the editform of the Invoices List , I added a link next to the IT Vendor dropdown on to call an AddVendor JavaScript function.

<The AddVendor function Opens the IT Vendors/NewForm.aspx in a Modal window , and sets a callback so that another function ‘VendorAdded ‘ is called when the user closes the modal.

<td width="400px" valign="top" class="ms-formbody">
							<table border="0" cellspacing="0" width="100%">
								<tr>
									<td>
										<SharePoint:FormField runat="server" id="ff4{$Pos}" ControlMode="Edit" FieldName="ITVendor" __designer:bind="{ddwrt:DataBind('u',concat('ff4',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@ITVendor')}"/>
										<SharePoint:FieldDescription runat="server" id="ff4description{$Pos}" FieldName="ITVendor" ControlMode="Edit"/>
									</td>
									<td>
										<a   onclick="javascript:AddVendor()">Add Vendor</a>	
									</td>
								</tr>
							</table>
						</td>

// this function gets called when the user clicks the "Add Vendor Link"

function AddVendor(){

              //debugger;

              var siteUrl=SP.ClientContext.get_current().get_url();

              var options = SP.UI.$create_DialogOptions();

                options.title = "Add Vendor";

                options.url = siteUrl+"/Lists/IT Vendors/NewForm.aspx";

                options.dialogReturnValueCallback=VendorAdded;

                SP.UI.ModalDialog.showModalDialog(options);

}


 

In the VendorAdded function (that gets called when the user closes the modal) I re populate the dropdown using rest (sorry) , figure out the maximum ID in the dropdown list (that must be the one the user just added) and then select that item.

// this function gets when the user closes the Add Vendor Modal Dialog

function VendorAdded(value,returnValue){

                if (value == '1') {

       this.statusId = SP.UI

           .Status

           .addStatus("Vendor Added",

               "Yourr vendor has been sucessfully added.",

               true);

       SP.UI.Status.setStatusPriColor(this.statusId, "Green");

   }

   if (value == '0') {

       this.statusId = SP.UI

           .Status

           .addStatus("Vendor not added",

               "Your vendor was <b>not</b> added. Please try again.",

               true);

       SP.UI.Status.setStatusPriColor(this.statusId, "Green");

                }

   setTimeout(RemoveStatus, 6000);

     debugger;

   // now refresh the droopdown list of vendors-- if the Vendor List has leess than 20 Items, the dropdown list is rendered as a simple select and we use field "vendorDropDown",

   // otherwise, it's rendered as a textbox and a hiddentextbox (with some fancy behaviors) and we use fields vendorInput and hiddenVendorInput (vendor input holds the

   // display value and HiddenVendorInput holsd the ID;

 

   var vendorDropDown=$("select[Title=IT Vendor]")[0];

   if (vendorDropDown == null){

                var vendorInput = $("input[title='IT Vendor']")[0];

                var hiddenVendorInputFieldName = $("input[title='IT Vendor']").attr("optHid");

                var hiddenVendorInput = $("input[id='"+hiddenVendorInputFieldName +"']")[0];

   }

  

   var siteUrl=SP.ClientContext.get_current().get_url();

 

   $.ajax({

                   url: siteUrl+ "/_vti_bin/listdata.svc/ITVendors?$orderby=Title&$select=Title,Id",

       dataType: 'json',

       async: false,

                                success: function (data) {

                                                                //debugger;

                                                                var maxid=0;

                                                                var choices="";

                                                                if (vendorDropDown == null){

                                                                // , there were more than 20 items and I have to hack the textboxes/

                                                                                $.each(data.d.results,function(){

                                                                                               

                                                                                                if (this.Id > maxid){ // save the maximum ID value -- this is the one the user just added

                                                                                                                maxid=this.Id;

                                                                                                                vendorInput.value=this.Title;

                                                                                                                hiddenVendorInput.value=this.Id;

                                                                                                }

                                                                                                if (choices==""){

                                                                                                                choices=this.Title;

                                                                                                }

                                                                                                else

                                                                                                {

                                                                                                                choices=choices+"|"+this.Title;

                                                                                                }

                                                                                });

                                                                }

                                                                else {

                                                                                // if there are less than 20 Vendors vendorDropDown is used

                                                               //note that the page using this script must have EnableEventValidation="false" because we are dynamically adding elements to the vendor Dropdown list,

                                                               // I don't wan to do this globally, so I'm commenting out this code

                                                               return;

                                               vendorDropDown.options.length=0;

                                                                                $.each(data.d.results,function(){

                                                                                                debugger;

                                                                                                if (this.Id > maxid){ // save the maximum ID value -- this is the one the user just added

                                                                                                                maxid=this.Id;

                                                                                                }

                                                                                                vendorDropDown.options.add(new Option(this.Title,this.Id));

                                                                                });

                                                                                vendorDropDown.value=maxid; // set the dropdowns value to the item that was just added.

                                                                }

                                                                               

                                                               

       },

                   error:function (xhr, ajaxOptions, thrownError){  

                           alert(xhr.status + "returned when adding Vendor");

                           alert(thrownError);            

                   }

                });

}


 

This has been running fine in production for some time now. I’m currently working on implementing this using SPServices using the splookupAddNew feature with a completefunc. That would do what I did in my VendorAdded function.

 

I’ll post back once I got it worked out,(or more likely when I have questions).

Jun 27, 2012 at 7:57 PM

Mark, this could be made to work in spservices, but it would require openning a modal window which isnt going to work in 2007. Are you committed to having nothing in SPServices thats not compatable with 2007?

Coordinator
Jun 28, 2012 at 4:39 AM

Russ:

I'm not averse to putting things into SPServices that aren't compatible with 2007, but I'd always prefer a good fallback. That said, the clock is ticking on 2007. Lots of people still use it, of course, and SPServices may well be more important to them than the 2010 crowd.

M.

Jun 28, 2012 at 12:28 PM

Marc, you do remember that I have that EVIL solution to this in 2007 right? :-) The code Russ provided is great for 2010 since those options are available, but what's wrong with a little trickery if it gets the job done! Well, it has worked for me anyway!!

Coordinator
Jul 10, 2012 at 3:50 AM

I cannot avow or deny EVIL solutions. ;+)

M.

Sep 13, 2012 at 9:46 PM
Edited Sep 13, 2012 at 9:47 PM

Russ,

Thanks for this.

Did you ever get this working using using completefunc?  How about multi user apps, what happens if a vendor is added by another user before your VendorAdded() looks for the max vendor id?

Have you found the max id is not always the one added in the modal?  Perhaps a way around this would be to pass the id back from the modal using javascript in the callback args. 

http://www.sharepointdevelopment.me/2011/06/passing-data-to-and-from-sharepoint-modal-dialogs

To do that with the built-in default forms (since the code behind the save button is not in .aspx file)  I think you'd have to js .unbind and .bind the Save button.

I've not tried this, but that's what I gather from the following:

http://social.technet.microsoft.com/Forums/en-US/sharepoint2010programming/thread/ba06d5e5-8c4c-4bca-95f8-65f40c1b11fa/

http://social.msdn.microsoft.com/Forums/en-US/sharepointcustomization/thread/9846f63f-f83a-4842-b9a5-d25a730aa3c2/

For now, I'll go with your method and assume the maxid is the the same item added in the modal.  Let us know your progress.

Thanks,

Josh

Sep 13, 2012 at 11:19 PM

To avoid update conflicts, you can search for the latest id created by the current user.

Oct 25, 2012 at 6:48 PM

Russ thanks for this.  Havn't tried it yet, but for those who want to do this completely client-side (no SPD), you can add the link using script like so:

$("input[title='ITVendor']").parents("td.ms-formbody").append("<a onclick='javascript:AddVendor()'>Add Vendor</a>");

Where 'ITVendor' is the internal name of the lookup column.

Josh

Oct 26, 2012 at 10:33 AM
jbooker wrote:

Russ thanks for this.  Havn't tried it yet, but for those who want to do this completely client-side (no SPD), you can add the link using script like so:

$("input[title='ITVendor']").parents("td.ms-formbody").append("<a onclick='javascript:AddVendor()'>Add Vendor</a>");

Where 'ITVendor' is the internal name of the lookup column.

Josh

I appreciate your help. I tried this and the link doesnt show up. if you have time please review and tell me whats wrong thanks:

<script src="/_layouts/1033/jquery-1.7.1.js" type="text/javascript">

$(document).ready(function(){
$("input[title='Columns (fields)']").parents("td.ms-formbody").append("<a onclick='javascript:AddColumn()'>Add New Columns(fields)</a>");
});

// this function gets called when the user clicks the "Add Column Link"

function AddColumn(){

              //debugger;

              var siteUrl=SP.ClientContext.get_current().get_url();

              var options = SP.UI.$create_DialogOptions();

                options.title = "Add Column";

                options.url = siteUrl+"/Lists/fields/NewForm.aspx";

                options.dialogReturnValueCallback=ColumnAdded;

                SP.UI.ModalDialog.showModalDialog(options);

}

 

function ColumsAdded(value,returnValue){

                if (value == '1') {

       this.statusId = SP.UI

           .Status

           .addStatus("Column Added",

               "Your Column has been sucessfully added.",

               true);

       SP.UI.Status.setStatusPriColor(this.statusId, "Green");

   }

   if (value == '0') {

       this.statusId = SP.UI

           .Status

           .addStatus("Column not added",

               "Your Column was <b>not</b> added. Please try again.",

               true);

       SP.UI.Status.setStatusPriColor(this.statusId, "Green");

                }

   setTimeout(RemoveStatus, 6000);

     debugger;

   // now refresh the droopdown list of Columns-- if the Column List has leess than 20 Items, the dropdown list is rendered as a simple select and we use field "ColumnDropDown",

   // otherwise, it's rendered as a textbox and a hiddentextbox (with some fancy behaviors) and we use fields ColumnInput and hiddenColumnInput (Column input holds the

   // display value and HiddenColumnInput holsd the ID;

 

   var ColumnDropDown=$("select[Title=Columns (fields)]")[0];

   if (ColumnDropDown == null){

                var ColumnInput = $("input[title='Columns (fields)']")[0];

                var hiddenColumnInputFieldName = $("input[title='Columns (fields)']").attr("optHid");

                var hiddenColumnInput = $("input[id='"+hiddenColumnInputFieldName +"']")[0];

   }

  
   var siteUrl=SP.ClientContext.get_current().get_url();

 
   $.ajax({

                   url: siteUrl+ "/_vti_bin/listdata.svc/fields?$orderby=Title&$select=Title,Id",

       dataType: 'json',

       async: false,

                                success: function (data) {

                                                                //debugger;

                                                                var maxid=0;

                                                                var choices="";

                                                                if (ColumnDropDown == null){

                                                                // , there were more than 20 items and I have to hack the textboxes/

                                                                                $.each(data.d.results,function(){

                                                                                              

                                                                                                if (this.Id > maxid){ // save the maximum ID value -- this is the one the user just added

                                                                                                                maxid=this.Id;

                                                                                                                ColumnInput.value=this.Title;

                                                                                                                hiddenColumnInput.value=this.Id;

                                                                                                }

                                                                                                if (choices==""){

                                                                                                                choices=this.Title;

                                                                                                }

                                                                                                else

                                                                                                {

                                                                                                                choices=choices+"|"+this.Title;

                                                                                                }

                                                                                });

                                                                }

                                                                else {

                                                                                // if there are less than 20 Columns ColumnDropDown is used

                                                               //note that the page using this script must have EnableEventValidation="false" because we are dynamically adding elements to the field Dropdown list,

                                                               // I don't wan to do this globally, so I'm commenting out this code

                                                               return;

                                              ColumnDropDown.options.length=0;

                                                                                $.each(data.d.results,function(){

                                                                                                debugger;

                                                                                                if (this.Id > maxid){ // save the maximum ID value -- this is the one the user just added

                                                                                                                maxid=this.Id;

                                                                                                }

                                                                                                ColumnDropDown.options.add(new Option(this.Title,this.Id));

                                                                                });

                                                                                ColumnDropDown.value=maxid; // set the dropdowns value to the item that was just added.

                                                                }

                                                                              
                                                              

       },

                   error:function (xhr, ajaxOptions, thrownError){ 

                           alert(xhr.status + "returned when adding Column");

                           alert(thrownError);           

                   }

                });

}

</script>




 

 

Oct 26, 2012 at 4:18 PM

bcobra,

Correct me if I'm wrong: you have a List called 'Fields' and a column in that list being used as a lookup called:

'Columns (fields)'

I added such a field to a list on my site, then put this code in a CEWP on the NewForm.aspx and the link appeared.  Apparently this selector works with the field display name rather than internal named.

$(document).ready(function(){
$("input[title='Columns (fields)']").parents("td.ms-formbody").append("<a onclick='javascript:AddColumn()'>Add New Columns(fields)</a>");
});


Tell us more about where you are putting your code.

I can't say whether the rest of russ' code will work for you since the internal field name is not 'Columns (fields)'

because this has special characters and spaces, the internal field name is:

'Columns_x0020__x0028_fields_x002'

Also, when you rename a column in a list, the internal name stays the same so check the html output of the NewForm to confim the internal name.

 

Oct 29, 2012 at 10:43 AM

jbooker,

   Thanks for the response. You are correct about list =fields and lookup column = 'columns (fields)'. I am putting the code in a text file and adding it to a CEWP on the Newform.aspx and no link appears. I have also deleted the field and and renamed it to just 'columns' for simplicity sake. 

<script src="/_layouts/1033/jquery-1.7.1.js" type="text/javascript">
<script language="javascript" type="text/javascript">
$(document).ready(function(){
$("input[title='Columns']").parents("td.ms-formbody").append("<a onclick='javascript:AddColumn()'>Add New Columns(fields)</a>");
});
</script>

no link shows up.

here is the HTML output of newform.aspx for Column field:

<td valign="top" class="ms-formbody">
		<!-- FieldName="Columns"
			 FieldInternalName="Columns"
			 FieldType="SPFieldLookup"
		  -->
			<span dir="none"><select name="ctl00$m$g_ee5d5855_cb78_4116_a9d4_9e1cbe0912ba$ctl00$ctl05$ctl04$ctl00$ctl00$ctl04$ctl00$Lookup" id="ctl00_m_g_ee5d5855_cb78_4116_a9d4_9e1cbe0912ba_ctl00_ctl05_ctl04_ctl00_ctl00_ctl04_ctl00_Lookup" title="Columns">
					<option selected="selected" value="0">(None)</option>
					<option value="23">test</option>

				</select><br/></span>
			
			

Oct 29, 2012 at 2:28 PM

Sorry, the script works for lookups having more then 20 items in the lookup list because of the select box vs. compound controls for lookup columns.

The selector for your output would be:

$("select[title='Columns']").parents("td.ms-formbody").append("<a onclick='javascript:AddColumn()'>Add New Columns(fields)</a>");

 Alternatively, here is some script that uses a function 'DropdownCtl()' in SPServices to differentiate.  So it should work for any lookup column.

<script src="/_layouts/1033/jquery-1.7.1.js" type="text/javascript">
<script src="/_layouts/1033/jquery.SPServices-1.7.2.js" type="text/javascript">
<script language="javascript" type="text/javascript">
$(document).ready(function(){
var lookupColumn = "Columns"; //set your lookup column names here
var lookupSelect = new DropdownCtl(lookupColumn);
 $(lookupSelect.Obj).parents("td.ms-formbody").append("<a onclick='javascript:AddColumn()'>Add New Columns(fields)</a>");
}); 
</script>
Josh
Oct 30, 2012 at 11:38 AM
Edited Oct 30, 2012 at 12:01 PM

Josh,

    I got the code working with:

$("select[title='Columns']").parents("td.ms-formbody").append("<a onclick='javascript:AddColumn()'>Add New Columns(fields)</a>");

but not the spservices code. this is great progress! I really need the link to show up under a multi lookup picker. I got that to work using:

$("select[title='Columns possible values']").parents("td.ms-formbody").append("<a onclick='javascript:AddColumn()'>Add Columns</a>");

for the list box of possible vlaues. Does the above spservices function still need to come into play  when using a multi lookup picker, i.e. is simple vs compound control still an issue?

Thanks again for your help and thanks also to Russ for showing us the way.

 My only issue now is that Russ's codes doesnt accomodate a mulit lookup picker to send the newly added item into the refreshed list of the lookup field in the parent.  Any guidance would be greatly appreciated

 

 

Oct 30, 2012 at 12:38 PM

I think SPServices handles Multi-select lookups.  Of course SPServices doesn't add new items to the listbox, but it does identify the element on the form depending on the type of lookup.  Check your reference to SPServices.  The above code assumes you have this file in your layouts dir on web server. "/_layouts/1033/jquery.SPServices-1.7.2.js"  Look in that file for the function 'DropdownCtl()'.  It will give you hints on how to select the listbox using jQuery.

Russ' code add items to the drop downs like so: 

ColumnDropDown.options.add(new Option(this.Title,this.Id)); 

It should be the same syntax for adding to a list box.  Your trouble is getting the correct selector for the list box. (var ColumnDropDown = ?)  Again look at 'DropdownCtl()' function in SPServices.

Nov 1, 2012 at 6:00 PM
Edited Nov 1, 2012 at 6:05 PM

I too am looking for a solution to refresh a multiselect look up field.  When searching SPServices-1.7.2 I can not find a reference as described by jbooker.  There is the field type "SPFieldLookupMulti", but the field itself seems to be broken up not into inputs like russgove's code, but rather, selects.  Their titles being "ColumnDisplayName possible values", and "ColumnDisplayName selected values".

For the time being, I am simply refreshing the form by replacing the option callback line that creates the status, with;

options.dialogReturnValueCallback = Function.createDelegate(null, CloseCallback);

with the CloseCallback function at the bottom

function CloseCallback(result, target) {
        location.reload(true);
    }

Issue with this being that any changes made to the form prior to adding a new value to a dropdown will be erased on refresh.Any insight on getting the provided solution of rossgove to work on a multiselect lookup field would be much appreciated. Also, when I ran the orginal code with the status callback function I would get an error regarding RemoveStatus not being defined. When looking at the code I noticed it comes up in setTimeout(RemoveStatus, 6000);

Was the function

function RemoveStatus() { SP.UI.Status.removeStatus(this.statusId); }

Forgotten in the code? or is it not needed?

Dec 12, 2012 at 1:48 AM
Edited Dec 12, 2012 at 1:53 AM

Sorry I lost track of this thread. I think the code below should work for multi-select lookups

function CounterpartyAdded(value, returnValue) {
    // if user canceled out of the add dialog
    if (value == '0') {
        return;
    }
    
    var lastItemID = $().SPServices.SPGetLastItemId({ listName: "Counterparties" });  // th id o fthe item just added
    var vendorDropDown = $("select[Title='Counterparty selected values']")[0]; // the dropdown on the right(the selected items)
    if (vendorDropDown !== null) {
        var myQuery = "" + lastItemID + "";

        $().SPServices({
            operation: "GetListItems",
            async: false,
            listName: "Counterparties",
            CAMLViewFields: "",
            CAMLQuery: myQuery,
            completefunc: function (xData, Status) {
                //	$(xData.responseXML).SPFilterNode("z:row").each(function() {  THIS IS THE SYNTAX FOR THE NEWWRE JQERY jQuery 1.7+,  with 
                $(xData.responseXML).find("[nodeName='z:row']").each(function () {
                   vendorDropDown.options.add(new Option($(this).attr("ows_Title"), $(this).attr("ows_ID")));
                   // if ($(this).attr("ows_ID") === lastItemID) {
                   //    vendorDropDown.options.add(new Option($(this).attr("ows_Title"), $(this).attr("ows_ID")));
                   //
                   // }


                });
            }
        });

    }

I wrote a blogpost on using this technique (although I haven't yet updated it to work with Multi Selectes);
http://yetanothersharepointblog.wordpress.com/2012/11/07/adding-a-new-item-to-a-lookup-list-using-javascript-and-spservices/
Also, I wanted to point out that the call to $().SPServices.SPGetLastItemId should get the last item added by the CurrentUser, so you don't need to worry about concurrent updates.
Finally, we could probably get this working in sharepoint 2007 using Jquery Modal popups.
Dec 12, 2012 at 11:02 PM

So Russ do I point the options.dialogReturnValueCallback to this new function instead of the status update function?  The solution in your blog is a bit different then the one you posted above which I am using.

Dec 12, 2012 at 11:34 PM
Edited Dec 13, 2012 at 12:05 AM

Toga,,

The idea was that you would replace the originalcounterppartyadded  (or in this case vendoradded) function with this one.

The code above does NOT work. I spent some time working on this today. There are a few hidden fields that need to ve updated. I have the newly added item added to the select box on the left, but when you click save its not saving the new value. I need to figure out how to update those hidden input fields.

I'mm post back, hopefully tomorrow

Russ

 

BTW , what version of sharepoint are u using

Dec 13, 2012 at 3:44 PM

Heres a version that works with muklti select options pn my test environment (2010)/ To useit just set the dialogReturnValueCallback of your dialog options to your version of the function below.

function CounterpartyAdded(value, returnValue) {
    // if user canceled out of the add dialog
    if (value == '0') {
        return;
    }
  
    // get the id of the item the user just added note that spGetLastItemID gets the item added bu the CURRENT USER
    var lastItemID = $().SPServices.SPGetLastItemId({ listName: "TESTLOOKUP" });  // REPLACE TESTLOOKUP WITH THE NAME OF YOUR LOOKUPLIST 
    // get the listbox on the right that holds the values the user has selected
    var selectedValueDisplay = $("select[Title='TESTLOOKUPCOLUMNS selected values']")[0]; //REPLACE  TESTLOOKUPCOLUMNS WITH THE NAME OF YOUR COLUMN
    if (selectedValueDisplay !== null) {
    	// Get The item the user JUST Added
        var myQuery = "<Query><Where><Eq><FieldRef Name='ID' /><Value Type='Counter'>" + lastItemID + "</Value></Eq></Where></Query>";
        $().SPServices({
            operation: "GetListItems",
            async: false,
            listName: "TESTLOOKUP",  //REPLACE TESTLOOKUP WITH THE NAME OF YOUR LOOKUPLIST 
 
            CAMLViewFields: "",
            CAMLQuery: myQuery,
            completefunc: function (xData, Status) {
                // get the row returned (should only be one!)
                $(xData.responseXML).find("[nodeName='z:row']").each(function () {
				// add the item to the listbox on the left (the selected Values)
                var newOption=new Option($(this).attr("ows_Title"), $(this).attr("ows_ID"));
				///newOption.title=$(this).attr("ows_Title"); // need to set this also, for some reason
               selectedValueDisplay.options[selectedValueDisplay.length]=newOption;

                // now find the previous Input whose name or id  ends with 'MultiLookupPicker'
                // this contains  values that will get saved to the listitem
                var MultiLookupPicker=$(selectedValueDisplay).closest("span").find("input:[name$='MultiLookupPicker']");
				var s="";
				for (var i=0; i < selectedValueDisplay.options.length; i++)
				{
					if (s !="")
						s=s+"|t";
					s=s+selectedValueDisplay.options[i].value.replace("|","||");
					s=s+"|t";
					s=s+selectedValueDisplay.options[i].text.replace("|","||");
				}
			$(MultiLookupPicker)[0].value=s;
			debugger;

                });
            }
        });

    }
}
Dec 13, 2012 at 6:09 PM
Edited Dec 13, 2012 at 9:42 PM

You are awesome Russ! I will give it a try to see if I can get it working.  I am running a 2010 environment btw.

hmmm, the code isn't doing anything for me.  It has no errors in it, but will not update the multi-select lookup field.  I added Alerts to ensure it is trigger if an item was added or not and those are working correctly.  Here is the code I am using currently.

function AddVendor(){

              //debugger;
              var siteUrl=SP.ClientContext.get_current().get_url();
              var options = SP.UI.$create_DialogOptions();
                options.title = "Add Plan";
                options.url = siteUrl+"/Lists/Plans/NewForm.aspx?&ContentTypeId=0x0100D3793035842EF84E9C33D5C9AF5645D20200A0FA9F728D9DD14E801EC7DD8B31AB8F";
                options.dialogReturnValueCallback=PlanAdded;
                SP.UI.ModalDialog.showModalDialog(options);

}

 
    
function PlanAdded(value, returnValue) {
    // if user canceled out of the add dialog
    if (value == '0') {
    alert ("Nothing added");
        return;
    }
  else if (value == '1') {
  alert ("something added");
    // get the id of the item the user just added note that spGetLastItemID gets the item added bu the CURRENT USER
    var lastItemID = $().SPServices.SPGetLastItemId({ listName: "Plans" });  // REPLACE TESTLOOKUP WITH THE NAME OF YOUR LOOKUPLIST 
    // get the listbox on the right that holds the values the user has selected
    var selectedValueDisplay = $("select[Title='Plans selected values']")[0]; //REPLACE  TESTLOOKUPCOLUMNS WITH THE NAME OF YOUR COLUMN
    if (selectedValueDisplay !== null) {
    	// Get The item the user JUST Added
        var myQuery = "<Query><Where><Eq><FieldRef Name='ID' /><Value Type='Counter'>" + lastItemID + "</Value></Eq></Where></Query>";
        $().SPServices({
            operation: "GetListItems",
            async: false,
            listName: "Plans",  //REPLACE TESTLOOKUP WITH THE NAME OF YOUR LOOKUPLIST 
 
            CAMLViewFields: "",
            CAMLQuery: myQuery,
            completefunc: function (xData, Status) {
                // get the row returned (should only be one!)
                $(xData.responseXML).find("[nodeName='z:row']").each(function () {
				// add the item to the listbox on the left (the selected Values)
                var newOption=new Option($(this).attr("ows_Title"), $(this).attr("ows_ID"));
				//newOption.title=$(this).attr("ows_Title"); // need to set this also, for some reason
               selectedValueDisplay.options[selectedValueDisplay.length]=newOption;

                // now find the previous Input whose name or id  ends with 'MultiLookupPicker'
                // this contains  values that will get saved to the listitem
                var MultiLookupPicker=$(selectedValueDisplay).closest("span").find("input:[name$='MultiLookupPicker']");
				var s="";
				for (var i=0; i < selectedValueDisplay.options.length; i++)
				{
					if (s !="")
						s=s+"|t";
					s=s+selectedValueDisplay.options[i].value.replace("|","||");
					s=s+"|t";
					s=s+selectedValueDisplay.options[i].text.replace("|","||");
				}
			$(MultiLookupPicker)[0].value=s;
			debugger;

                });
            }
        });

    }
}
}

I noticed two things;
First, your code has these two lines

 var newOption=new Option($(this).attr("ows_Title"), $(this).attr("ows_ID"));
				//newOption.title=$(this).attr("ows_Title"); // need to set this also, for some reason

for that second line, you have a comment on it twice.  Although the first line has the same code, was this done intentionally?
Second,
for the MultiLookupPicker, you have the code selecting the closest span with that input.  The code shows 3 inputs back to back with that value contained in the end of the name.  Maybe it needs to point to a different one of those?
I appreciate all the help you have provided.  You've been doing some great some here.  Thanks!
Dec 13, 2012 at 11:11 PM
Edited Dec 13, 2012 at 11:30 PM

instead of editing my last reply for a 3rd time, thought I'd update in a clean post.

I've been testing things with alerts and noticed that it isn't triggering the main part of the code.

at these lines it seems to not work;

    var selectedValueDisplay = $("select[Title='Plans selected values']")[0]; //REPLACE  TESTLOOKUPCOLUMNS WITH THE NAME OF YOUR COLUMN
    if (selectedValueDisplay !== null) {
    alert("SelectedValueDisplay is not null");

After the if statement, the alert I set does not trigger.  Is this portion of code correct? It seems to find and set selectedValueDisplay to something, but it isn't a string or integer because it doesn't alert like one.

UPDATE:
I set the if statement to a (1 === 1) so it will pass and it still doesn't add the item.  So although this portion needs to be looked at, it doesn't seem to be the root cause...

Dec 14, 2012 at 12:49 AM

So you dont get the the alert saying  SelectedValueDisplay is not null"?

Browse to your page, then hit F12 to bring up ie developer tools (um.. u r using ie, right?). In developer tools from the menu select Find--> Select element by click, Then go back toe the browser and click on the 'selected items' listbox. Now switch back to developer tools .

Look around the selected tag, a few lines up you should see a select tag with the Title of ''Plans selected values'. Actually, if your alert is not firing, your select box may be  worder slihtly differently , maybe 'Plan selected value' or  'plans selected value' .  Whatever, you need to fine the title of that '??? selected values' control and plug it into the javascript line  var selectedValueDisplay = $("select[Title='Plans selected values']")[0];

PS are you using ie? what version?

 

 

 

Dec 14, 2012 at 5:35 PM
Edited Dec 14, 2012 at 5:36 PM

Correct, the alert does not pop-up.  I am using IE, and already did as you described when I first set the variable.  It is "Plans selected values" as its title.

As I mentioned, I changed the if statement from;

if (selectedValueDisplay !== null) {

to

if (1 === 1) {

for testing purposes.  When I did this, the if statement results as true, and the alert pop-ups saying "SelectedValueDisplay is not null", but the multi select still does not update like it should after the rest of the code is ran.

Dec 14, 2012 at 11:39 PM

If the variable selectedValueDisplay is null (which it appears to be) then  the jqery selector:

$("select[Title=Plans selected values']")

is not finding  anything. If that selector doesnt work, we cant find the select control and nothing will work.

can you do a view source on your page and  find the select box whose title is 'Plans selected values'?

Copy the 10 lines above and below it and paste it here and we can figure out why that selector is not working.

 

 

Dec 15, 2012 at 12:48 AM
Edited Dec 15, 2012 at 12:54 AM

Not sure this is helpful since "view source" doesn't seem to show the Title's of the inputs

 
<td valign="top" class="ms-formbody">
		<!-- FieldName="Plans"
			 FieldInternalName="Plans"
			 FieldType="SPFieldLookupMulti"
		  -->
			<span dir="none">
		<input id="ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker" name="ctl00$m$g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f$ctl00$ctl05$ctl44$ctl00$ctl00$ctl04$ctl00$ctl00$MultiLookupPicker" type="hidden"></input><input id="ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_data" name="ctl00$m$g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f$ctl00$ctl05$ctl44$ctl00$ctl00$ctl04$ctl00$ctl00$MultiLookupPicker$data" type="hidden" value=*REMOVED TO CONDENSE*></input><input id="ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_initial" name="ctl00$m$g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f$ctl00$ctl05$ctl44$ctl00$ctl00$ctl04$ctl00$ctl00$MultiLookupPicker$initial" type="hidden" value="*Removed for condensing*"></input>
		<table class="ms-long" cellpadding="0" cellspacing="0" border="0">
			<tr>
				<td class="ms-input">
					<select name="ctl00$m$g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f$ctl00$ctl05$ctl44$ctl00$ctl00$ctl04$ctl00$ctl00$SelectCandidate" id="ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_SelectCandidate" multiple="multiple" title="Plans possible values" onchange="GipSelectCandidateItems(ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m);" ondblclick="GipAddSelectedItems(ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); return false" style="width:143px;height:125px;overflow:scroll;">
				</select>
				</td>
				<td style="padding-left:10px">
				<td align="center" valign="middle" class="ms-input"><button id="ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_AddButton" class="ms-ButtonHeightWidth" onclick="GipAddSelectedItems(ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); return false"> Add > </button><br />
					<br /><button id="ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_RemoveButton" class="ms-ButtonHeightWidth" onclick="GipRemoveSelectedItems(ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); return false"> < Remove </button>
				</td>
				<td style="padding-left:10px">
				<td class="ms-input">
					<select name="ctl00$m$g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f$ctl00$ctl05$ctl44$ctl00$ctl00$ctl04$ctl00$ctl00$SelectResult" id="ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_SelectResult" multiple="multiple" title="Plans selected values" onchange="GipSelectResultItems(ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m);" ondblclick="GipRemoveSelectedItems(ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); return false" style="width:143px;height:125px;overflow:scroll;">
				</select>
				</td>

Here is the code from pressing F12,

<select name="ctl00$m$g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f$ctl00$ctl05$ctl44$ctl00$ctl00$ctl04$ctl00$ctl00$SelectResult" title="Plans selected values" id="ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_SelectResult" style="width: 250px; height: 125px; overflow: scroll;" ondblclick="GipRemoveSelectedItems(ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m); return false" onchange="GipSelectResultItems(ctl00_m_g_c76eb6da_9e12_4b19_8eee_80863f9f7c2f_ctl00_ctl05_ctl44_ctl00_ctl00_ctl04_ctl00_ctl00_MultiLookupPicker_m);" multiple="multiple">

As you can see, it has the title as "Plans selected values"

For the "addVendor" function you wrote, I am using the method provided to put a link directly into the form. It is actually using the same "select[title=" that your new code uses. The following works fine in my form.

$("select[title='Plans selected values']").parents("td.ms-formbody").append("Add New Plan");
});

So why does this code work using the $("select[title='Plans selected values']"). but the other doesnt?

Dec 15, 2012 at 1:36 AM
Edited Dec 15, 2012 at 2:02 AM

Ahhh....so that dosent make sense, the $("select[title='Plans selected values']") in one spot, but noy in another. it must be the context the method is called from.

I suspect  when you're making the $("select[title='Plans selected values']") call that doesnt work, the document hasnt been fully loaded. Is your call wrapped in a $(document).ready(){} function? can you post your full code here?

The code in my blog is different from what I posted here, and I anwered your question  thinking you were using the method posted in the blog.

If youre adding the link via

<td>
<a   onclick="javascript:AddVendor()">Add Vendor</a>
</td>

the dom  may not have been loaded. Don't customize the html as described above, instead add the link using javascript as shown in the blog:

function setupAddNew() {
    //debugger;

    var selectTD = $("select[Title='Counterparty']").parent();
 
      selectTD.append('   ')//  this should be an <image src='whatever' onclick='javascript:addPlans()' /
    .append("Add Counterparty");

}

function documentLoaded() {
    setupAddNew();
    //debugger;
}
_spBodyOnLoadFunctionNames.push("documentLoaded");

The spBodyOnLoad.. stuff will call the documentLoaded function when every thing is ready. Document loaded wil call setupAddNew.  setupAddNew creates a link to the 'addPlans()' method.

 

 

Jan 18, 2013 at 11:07 PM

Hey Toga,

I'm not sure how you made out, but I created a reusable version of the code that works with multi-select lookups ,

you just need to call a method

setupAddNew(

"Material Type", "TypesOfMaterial", "/Lists/TypesOfMaterial/NewForm.aspx", "Title", "ows_Title" ,true

);

That last parameter of true, makes it work with multi-selectes.

http://code.msdn.microsoft.com/Javascript-to-add-an-Add-60b6299b

hth,

Russell