/* Copyright (C) 2011 by Sincera Solutions, Inc. If you find this script helpful to you, and especially if you end up using it, we'd appreciate a like, vote up, heart, or whatever else is appropriate on the site that you found the code. Failing all that, drop us a line at support@sincerasolutions.com to let us know you found it useful. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /// function wireUpCountryAndStateFields(countryFieldName, stateFieldName) { /// Turns a pair of country and stateOrProvince controls into dependent dropdown lists. /// Name of the Country field to change. 'country' or 'address1_country' are typical. /// Name of the StateOrProvice field to change. 'stateorprovince' or 'address1_stateorprovince' are typical. wireUpCountryField(countryFieldName, stateFieldName); } function wireUpCountryField(countryFieldName, stateFieldName) { /// Configures the country field to be a dropdown based on the Country object. /// Name of the Country field to change. 'country' or 'address1_country' are typical. /// Name of the StateOrProvice field whose values depend on this country field. 'stateorprovince' or 'address1_stateorprovince' are typical. var $countryField = $('#' + countryFieldName); if ($countryField.length < 1) return; // hide the existing textbox $countryField.hide(); var selectedCountry = $countryField.val(); var countryRequirementLevel = Xrm.Page.getAttribute(countryFieldName).getRequiredLevel(); countryRequirementLevel = countryRequirementLevel == "required" ? 2 : countryRequirementLevel == "recommended" ? 1 : 0; var $countryDropdown = generateSelectBox('ddl_' + countryFieldName, countryRequirementLevel, Countries, selectedCountry); // add the generated dropdown to the cell where the textbox was $('#' + countryFieldName + '_d').append($countryDropdown); // bind a function to the change event on the dropdown so we can populate the real field's value $countryDropdown.change({ 'countryFieldName': countryFieldName, 'stateFieldName': stateFieldName }, handleCountryChanged); // wire up the state field based on the currently selected country wireUpStateField(stateFieldName, selectedCountry); } function wireUpStateField(stateFieldName, selectedCountry) { /// Configures the stateOrProvince field to be a dropdown dependent on the value of the country dropdown. Values are pulled from the Countries object. /// Name of the StateOrProvice field to change. 'stateorprovince' or 'address1_stateorprovince' are typical. /// Name of the selected country, which is used to determine which states should be shown. var stateAttr = Xrm.Page.getAttribute(stateFieldName); var selectedState = stateAttr == null ? "" : stateAttr.getValue(); var states = getStatesForCountry(selectedCountry); var $stateField = $('#' + stateFieldName); // if states aren't known, leave the textbox around if (states == null || !$.isArray(states) || states.length < 1) { $('#ddl_' + stateFieldName).remove(); $stateField.show(); return; } // we have values for a dropdown, so hide the textbox field $stateField.hide(); var stateRequirementLevel = Xrm.Page.getAttribute(stateFieldName).getRequiredLevel(); stateRequirementLevel = stateRequirementLevel == "required" ? 2 : stateRequirementLevel == "recommended" ? 1 : 0; var $stateDropdown = generateSelectBox('ddl_' + stateFieldName, stateRequirementLevel, states, selectedState); // if there isn't a dropdown already, create it // otherwise, replace it so that the controls won't flash in the browser var $existingDropdown = $('#ddl_' + stateFieldName); if ($existingDropdown.length < 1) $('#' + stateFieldName + '_d').append($stateDropdown); else $existingDropdown.replaceWith($stateDropdown); // bind a function to the change event on the dropdown so we can populate the real field's value $stateDropdown.change({ 'stateFieldName': stateFieldName }, handleStateChanged); // fire the change event in case the existing value of the field is not available in the new dropdown values $stateDropdown.change(); } function getStatesForCountry(selectedCountry) { /// Finds the states that go with selectedCountry, using the Countries object. /// The name (not abbr) of the country that is selected. /// Returns an array of states/provinces belonging to the selected country, or an empty array if they have not been configured. for (i in Countries) { var country = Countries[i]; if (selectedCountry == country.name) return country.states; } return []; } function handleCountryChanged(eventData) { /// Sets the value of the country field to the newly selected value and reconfigures the dependent state dropdown. /// jQuery handles this parameter, which contains the names of the fields that should be acted upon. var stateFieldName = eventData.data.stateFieldName; var selectedCountry = setFieldFromDropdown(eventData.data.countryFieldName); wireUpStateField(stateFieldName, selectedCountry); } function handleStateChanged(eventData) { /// Sets the value of the stateOrProvince field to the newly selected value. /// jQuery handles this parameter, which contains the names of the fields that should be acted upon. setFieldFromDropdown(eventData.data.stateFieldName); } function setFieldFromDropdown(fieldName) { /// Sets a field's value based on a related dropdown's value. /// Name of the field to set. The dropdown to get the value from is assumed to be this parameter prefixed with 'ddl_'. /// The value that was selected in the dropdown. var $dropdown = $('#ddl_' + fieldName); if ($dropdown.length != 1) return null; var selectedValue = $dropdown.find('option:selected:first').val(); var attr = Xrm.Page.getAttribute(fieldName); if (attr != null) attr.setValue(selectedValue); return selectedValue; } function generateSelectBox(id, requirementLevel, options, selectedValue) { /// Generates a new select box with appropriate attributes for MS CRM 2011. /// Unique ID the new select element will have. /// Requirement level for the field, which will be set on the select element's attributes and used by CRM. 0 for 'none', 1 for 'recommended', 2 for 'required'. /// An array of the options, each one following this format: { "name": "Display value for dropdown", "abbr": "Value that isn't actually stored in the field but could easily be changed to be, if you want it to" }. /// If an option is found whose 'name' property matches this string, it will be selected in the dropdown. var $ddl = $(''); $ddl.append(jQuery('