I am using CRM 2013 On premise, and in it there is an attribute which has an option set (not global) having text and value as "Dummy Entry" "0". Default Value is unassigned.
My code is to add options in this option set with some business logic. So I can add new options in it via Javascript.
When I am adding Options in it via Javascript, it is not allowing me to change the value lets say
Option1 val1
Option2 val1 is added then it wont allow me to select these values and every-time selecting them will revert to default entry "--" and nothing will change.
But lets say I add
"Option1" "0"
"Option2" "0"
as text and values, they are shown finely and selecting any of them changes the text to "Dummy Entry".
Basically somehow if the value exists in the list of Options (which are static and not added via JS), it is accepting and selecting it and showing text from it.
If the value is not found in the static option list, it doesnt select anything and show default "--"
I hope I am clear, please let me know in case of any confusion. The following snippet is working in CRM 2011 while not working in CRM 2013.
// testing function
populateBundleLists: function () {
var bundleListControl = Xrm.Page.getControl("XXX_bundlelist");
var bundleOptions = bundleListControl.getAttribute().getOptions();
var bundleOption = bundleOptions[0];
bundleListControl.clearOptions();
// add some arbitrary values to control
for (var i = 1; i <= 7; i++) {
bundleOption.value = i;
bundleOption.text = 'Dummy bundle ' + i.toString();
bundleListControl.addOption(bundleOption, i - 1);
}
},
CRM stores OptionSets in the entity configuration and will need to know about all of the possible values. You cannot add new options using JS b/c the system will not be able to resolve your new value when someone queries using a different mechanism (Fetch XML, Advanced Find, filtered view, etc).
Related
I am trying to use the Multiselect option set and want to build it dynamically, the addOption() is populating the multiselect field correctly, but on save of record it is prompting the validation error.
On change of contact lookup, I am populating the abc_multiselect field. It is populating fine dynamically then user selects the required options from multiselect field, but on save of record (Ribbon Save button not custom save event of form) the CRM is not accepting the values.
MSCRM Version
Server version: 9.2.22081.00182
Client version: 1.4.4647-2208.1
function polulate(executionContext){
var formContext = executionContext.getFormContext();
var multiselect = formContext.getControl("abc_multiselect");
var high = {value : 895390001, text : "High"};
multiselect.addOption(high);
}
The error is;
On Popup
One or more of the option values for this picklist are not in the range of allowed values.
Details
Exception Message: A validation error occurred. The value 895390001 of 'abc_multiselect' on record of type 'abc_ENTITY' is outside the valid range. Accepted Values:
ErrorCode: -2147204326
HexErrorCode: 0x8004431a
ErrorDetails:
ApiExceptionSourceKey: Plugin/Microsoft.Crm.ObjectModel.TargetAttributeValidationPlugin
ApiStepKey: fc743e7d-fbea-4695-bdb9-7d78334c8474
ApiDepthKey: 1
ApiActivityIdKey: 3907c6d7-ef4a-437e-946f-55e0f956fc3e
ApiPluginSolutionNameKey: System
ApiStepSolutionNameKey: System
ApiExceptionCategory: ClientError
ApiExceptionMessageName: PicklistValueOutOfRange
ApiExceptionHttpStatusCode: 400
HelpLink: http://go.microsoft.com/fwlink/?LinkID=398563&error=Microsoft.Crm.CrmException%3a8004431a&client=platform
TraceText:
[Microsoft.Crm.ObjectModel: Microsoft.Crm.ObjectModel.TargetAttributeValidationPlugin]
[fc743e7d-fbea-4695-bdb9-7d78334c8474: TargetAttributeValidationPlugin]
Activity Id: 28d5f67f-bf24-4eca-9124-cf95cf06dc30
I also tried to make all option set values hard coded (Added during the multiselect field creation), it worked smoothly. No issue ! But on dynamically population; on save, the CRM is not accepting the values.
I have tried this , this, this and this but all in vain.
Any one can guide, what is missing?
Update 1
function polulate(executionContext){
var formContext = executionContext.getFormContext();
var multiselect = formContext.getControl("abc_multiselect");
multiselect.clearOptions();
var high = {value : 895390001, text : "High"};
multiselect.addOption(high);
}
I also checked by changing the value from 895390001 to 895390000 and even to 100 and 101 but still same issue.
https://stackoverflow.com/a/48011975/5436880
This should solve your issue? most probably option set does not have 895390001 or it is already selected. you could also try to clear all option sets and then add
clear options
For using addOption those options need to be there in metadata first. You cannot add an option that is not present in metadata. Example can be Suppose you have Option A, 1 and 3 in Metadata. now you want to add another option 4 using Javascript "addOption", it is not possible.
In your case, get a maximum possible set or options in the optionset now onload of form or Onchange of field "removeOption " the options that are not required.
I have already implement auto number with plugin, and it is through another entity type to ensure all operations are in one transaction.
but I have another question, that is can we use process lock(eg. mutex) to fix it? this will more flexible than before, isn't it?
Dynamics 365 has native support for auto-numbering fields since v9.0, with the minor inconvenience of having to manipulate them through code only.
Unless it's a broken feature (it happens), there's no need for custom autonumbers anymore.
https://learn.microsoft.com/en-us/dynamics365/customer-engagement/developer/create-auto-number-attributes
Example:
CreateAttributeRequest widgetSerialNumberAttributeRequest = new CreateAttributeRequest
{
EntityName = "newWidget",
Attribute = new StringAttributeMetadata
{
//Define the format of the attribute
AutoNumberFormat = "WID-{SEQNUM:5}-{RANDSTRING:6}-{DATETIMEUTC:yyyyMMddhhmmss}",
LogicalName = "new_serialnumber",
SchemaName = "new_SerialNumber",
RequiredLevel = new AttributeRequiredLevelManagedProperty(AttributeRequiredLevel.None),
MaxLength = 100, // The MaxLength defined for the string attribute must be greater than the length of the AutoNumberFormat value, that is, it should be able to fit in the generated value.
DisplayName = new Label("Serial Number", 1033),
Description = new Label("Serial Number of the widget.", 1033)
}
};
_serviceProxy.Execute(widgetSerialNumberAttributeRequest);
Docs point out that
The sequential segment is generated by SQL and hence uniqueness is guaranteed by SQL.
XrmToolbox should have a plugin to manage auto number fields (thus making it easier), but I haven't tried it.
Plugin's can be run on multiple machines concurrently depending on your installation - that's why the entity (database) lock is regularly used.
I am looking to add a Multi select optionset in a CRM 2016 entity form. As Multi select optionset is not an available out of box field type (we have optionset, two options available).
How to create this particular field type?
(P.S. - I have tried some Javascript to enable optionset as multi select but having troubles here. Is there a way other than this?)
In addition to DotNetPro answer, would like to mention next Dynamics CRM 365 (online) update # July 2017 will have new datatype: Multi-select optionset
For now, N:N relationship will give you supported customizations.
If you are using Matre blog, consider Shaik's reply on this thread.
You might want to also consider using editable sub-grids to create child records which simply have the option set on.
There is no out of the box support for multi-select pick lists in Dynamics CRM but since the latest UI improvements in CRM2016 you can use a standard N:N Relationship with form sub-grid to get a most respectable multiple selection form field.
You can try some JavaScript that will convert the OptionSet to Multi-select but these will be un-supported customization's and the functionality could break in future upgrades.
Sample Code on the 2nd Url below:
//Coverts option list to checkbox list.
function ConvertDropDownToCheckBoxList() {
var dropdownOptions = parent.Xrm.Page.getAttribute("new_makeyear").getOptions();
var selectedValue = parent.Xrm.Page.getAttribute("new_selectedyears").getValue();
$(dropdownOptions).each(function (i, e) {
var rText = $(this)[0].text;
var rvalue = $(this)[0].value;
var isChecked = false;
if (rText != '') {
if (selectedValue != null && selectedValue.indexOf(rvalue) != -1)
isChecked = true;
/* Remove spaces before input, label word and end tags of input & label*/
var checkbox = "< input type='checkbox' name='r'/ >< label> " + rText + "</ label>"
Simple multi-select lists in CRM 2013
There is no out of the box support for multi-selec
Convert Option set to multi select Checkbox list
I'm currently trying to implement AJAX results filtering on a certain page.
I created the dropdowns(on the client side), so that they have the umbraco prevalue id as their value.
I will then send this id to the server, rather than the text value. Then I loop through my content to find items with this same id.
The problem, however, is that I can't figure out how to get the value id from the property. Everything either returns the text value, or just a 0 value.
This is being performed in an ApiController.
These are all of the options I've tried:
IPublishedContent root = Umbraco.TypedContentAtRoot().First();
var downloads = root.Children.Where(q => q.Name == "Downloads").SingleOrDefault();
foreach (var item in downloads.Children)
{
var test = item.GetPropertyValue<int>("classification");
var testing = item.GetProperty("classification");
var testVal = testing.DataValue;
var testValToo = testing.GetValue<int>();
var testThree = testing.Value;
}
These are the results in order:
- 0
- IPublishedProperty
- "textValue"
- 0
- "textValue"
Is it possible to get the selected value id from a dropdownlist property? Or is string matching my only option to compare values?
EDIT:
Nevermind, found the solution. Posting the answer here, in case someone else needs it.
I was using the data type dropdownlist. I should have been using dropdownlist:publishing keys.
dropdownlist only ever returns a value. dropdownlist:publishing keys, however, returns the prevalue id, rather than the text value.
Source
Something like this perhaps.
library.GetPreValueAsString(node.GetProperty<int>("sectionType")).ToLower()
My main question here is dealing with the pramas map when having a one-to-many relationship managed within one dynamic form, as well as best practices for dealing with one-to-many when editing/updating a domain object through the dynamic form. The inputs for my questions are as follows.
I have managed to hack away a form that allows me to create the domain objects shown below in one Dynamic form, since there is no point in having a separate form for creating phone numbers and then assigning them to a contact, it makes sense to just create everything in one form in my application. I managed to implement something similar to what I have asked in my Previous Question (thanks for the people who helped out)
class Contact{
String firstName
String lastName
// ....
// some other properties
// ...
static hasMany = [phones:Phone]
static mapping = {
phones sort:"index", cascade: "all-delete-orphan"
}
}
class Phone{
int index
String number
String type
Contact contact
static belongsTo = [contact:Contact]
}
I basically managed to get the values from the 'params' map and parse them on my own and create the domain object and association manually. I.e. i did not use the same logic that is used in the default scaffolding, i.e.
Contact c = new Contact(params)
etc...., i just looped through all the params and hand crafted my domain objects and saved them and everything works out fine.
My controller has code blocks that look like this (this is stripped down, just to show a point)
//create the contact by handpicking params values
def cntct = new Contact()
cntct.firstName = params.firstName
cntct.lastName = params.lastName
//etc...
//get array of values for number,type
def numbers = params['phone.number']
def types = params['phone.type']
//loop through one of the arrays and create the phones
numbers.eachWithIndex(){ num, i ->
//create the phone domain object from
def phone = new Phone()
phone.number = num
phone.type = types[i]
phone.index = i
cntct.addToPhones(phone)
}
//save
My questions are as follows:
What is the best practice of handeling such a situation, would using Command objects work in this case, if yes where can i found more info about this, all the examples I have found during my search deal with one-to-one relationships, I couldn't find an example for one-to-many?
What is the best way to deal with the relatiohsips of the phones in this case, in terms of add/removing phones when editing the contact object. I mean the creation logic is simple since I have to always create new phones on save, but when dealing with updating a contact, the user might have removed a phone and/or editing an exiting one and/or added some new phones. Right now what I do is just delete all the phones a contact has and re-create them according to what was posted by the form, but I feel that's not the best way to do it, I also don't think looping over the existing ones and comparing with the posted values and doing a manual diff is the best way to do it either, is there a best practice on how to deal with this?
Thanks, hopefully the questions are clear.
[edit] Just for more information, phone information can be added and deleted dynamically using javascript (jquery) within the form [/edit]
disclaimer: i do not know if the following approach works when using grails. Let me know later.
See better way for dynamic forms. The author says:
To add LineItems I have some js that calculates the new index and adds that to the DOM. When deleting a LineItem i have to renumber all the indexes and it is what i would like to avoid
So what i do
I have a variable which stores the next index
var nextIndex = 0;
When the page is loaded, i perform a JavaScript function which calculates how many child The collection has and configure nextIndex variable. You can use JQuery or YUI, feel free.
Adding a child statically
I create a variable which store the template (Notice {index})
var child = "<div>"
+= "<div>"
+= "<label>Name</label>"
+= "<input type="text" name=\"childList[{index}].name\"/>"
+= "</div>"
+= "</div>"
When the user click on the Add child button, i replace {index} - by using regex - by the value stored in the nextIndex variable and increment by one. Then i add to the DOM
See also Add and Remove HTML elements dynamically with Javascript
Adding a child dinamically
Here you can see The Paolo Bergantino solution
By removing
But i think it is the issue grow up when deleting. No matter how many child you remove, does not touch on the nextIndex variable. See here
/**
* var nextIndex = 3;
*/
<input type="text" name="childList[0].name"/>
<input type="text" name="childList[1].name"/> // It will be removed
<input type="text" name="childList[2].name"/>
Suppose i remove childList1 What i do ??? Should i renumber all the indexes ???
On the server side i use AutoPopulatingList. Because childList1 has been removed, AutoPopulatingList handles it as null. So on the initialization i do
List<Child> childList = new AutoPopulatingList(new ElementFactory() {
public Object createElement(int index) throws ElementInstantiationException {
/**
* remove any null value added
*/
childList.removeAll(Collections.singletonList(null));
return new Child();
}
});
This way, my collection just contains two child (without any null value) and i do not need to renumber all the indexes on the client side
About adding/removing you can see this link where i show a scenario wich can gives you some insight.
See also Grails UI plugin
Thanks,
Your answer brought some insight for me to do a wider search and I actually found a great post that covers all the inputs in my question. This is just a reference for anyone reading this. I will write a blog entry on how I implemented my case soon, but this link should provide a good source of ino with a working exmaple.
http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/
Most of the time I use ajax to manage such problem.
So when the user clicks add new phone I get the template UI from the server for manageability purpose ( the UI just same GSP template that I use to edit, update the phone), so this way you are not mixing your UI with your js code, whenever you want to change the UI you have to deal only with our GSP code.
Then after getting the UI I add it to the page using jquery DOM manipulation. Then after filling the form when they hit add(save) the request is sent to the server via ajax and is persisted immediately.
When the user clicks edit phone the same UI template is loaded from the server filled with existing phone data, then clicking update will update the corresponding phone immediately via ajax, and same thing applies to delete operation.
But one day I got an additional scenario for the use case that says, "until I say save contact no phone shall be saved on the backend, also after adding phones to the contact on the ui if navigate away to another page and come back later to the contact page the phones I added before must be still there." ugh..
To do this I started using the Session, so the above operations I explained will act on the phone list object I stored on the session instead of the DB. This is simple perform all the operation on the phonesInSession but finally dont forget to do this(delete update):
phonesToBeDeleted = phonesInDB - phonesInSession
phonesToBeDeleted.each{
contact.removeFromPhones(it)
it.delete()
}
I know I dont have to put a lot of data in session but this is the only solution I got for my scenario.
If someone has got similar problem/solution please leave a comment.
First, in all your input fields names you add an #:
<input type="text" name="references[#].name"/>
Second, add call a function before submitting:
<g:form action="save" onsubmit="replaceAllWildCardsWithConsecutiveNumbers();">
Third, this is the code for the function that you call before submitting the form:
function replaceAllWildCardsWithConsecutiveNumbers(){
var inputs = $('form').find("[name*='#']");
var names = $.map(inputs, function(el) { return el.name });
var uniqueNames = unique(names);
for (index in uniqueNames) {
var uniqueName = uniqueNames[index];
replaceWildCardsWithConsecutiveNumbers("input", uniqueName);
replaceWildCardsWithConsecutiveNumbers("select", uniqueName);
}
}
function unique(array){
return array.filter(function(el, index, arr) {
return index === arr.indexOf(el);
});
}
function replaceWildCardsWithConsecutiveNumbers(inputName, name){
counter = 0;
$(inputName + "[name='" + name + "']").each(function (i, el) {
var curName = $(this).attr('name');
var newName = curName.replace("#", counter);
$(this).attr('name', newName);
counter += 1;
});
}
Basically, what the code for replaceAllWildCardsWithConsecutiveNumbers() does, is to create a list for all input (or select) elements whose name contains an #. Removes the duplicates. And then iterates over them replacing the # with a number.
This works great if you have a table and you are submitting the values to a command object's list when creating a domain class for the first time. If you are updating I guess you'll have to change the value of counter to something higher.
I hope this helps someone else since I was stuck on this issue for a while myself.