How to dynamically/conditionally change the Required property of a ticket form field?
I have not yet discovered how to access the fields' Required property after the form is rendered, or how to inform the validation function that this property has changed. So it is time to ask.
All too often, I receive the question "why isn't this field required?" and I must answer "it can't be, or else it would have to be filled in when the ticket is first created, and it is not known at that point in the process."
Best Answers
-
Cory_Bowe Customer Adept IT Monkey ✭✭@Tom_Hendricks-
You can either set the items as required in the form and then remove it under certain circumstances or don't make it required and set the attribute.
To remove:$("elementselectors").removeAttr('required');
To add:
$("elementselectors").prop('required', true);
You can trigger these events off of many different items with JS, as an example, when a kendo dropdown changes you can run a function to check the value://Get our inputbox as a semi-useless jquery object, using wildcard guid search on the data-bind attribute.var kendoPriority = $('[data-control-sourceid="d9c24cbf-c515-4a41-ae0f-7c4fdc3a10b5"]');//Get the kendo Tree object by randomly guessing it's v3 version of the dropdown.var kendoPriorityDropdownTree = kendoPriority.getKendoExtDropDownTreeViewV2();//Get the actual kendo dropdown object, so we can bind a change eventvar priorityTreeView = kendoPriorityDropdownTree.treeview();//Using http://docs.telerik.com/kendo-ui/api/javascript/ui/treeview , add a change event.priorityTreeView.bind("change", yourFunctionToRun);5 -
Cory_Bowe Customer Adept IT Monkey ✭✭@Tom_Hendricks - The code example that I shared is straight from a Cireson examples document minus the bind event. I believe the difference is in the getKendoExtDropDownTreeV2 vs kendoDropDownTree.
Edit: I misread your statement, it should be the plain vanilla DOM elements, correct.5 -
Cory_Bowe Customer Adept IT Monkey ✭✭@Tom_Hendricks-
I believe it depends on the type of element that you are trying to set required, ie textarea vs dropdown. If the element has a paired hidden input field you also need to control the required attribute on it.
I'm not sure what piece isn't working for you, but you could try this instead of the .prop method:$("elementselectors").attr('required', true);5 -
Tom_Hendricks Customer Super IT Monkey ✭✭✭✭✭@Cory_Bowe, I just figured it out, and you were very close with your last comment. The DIV that encloses the entire control (label and all) also has the "required" attribute. I missed it the first time through (blame multitasking...).
Keeping with my example, $('input[name="RequestedWorkItem"]').parent().parent().removeAttr('required') will take care of it, after it has also been removed from the input element itself. I have yet to test this with other controls to see if they have different placement of the attribute, which would cause me to write this differently. The label was already taken care of near the top of this thread.
I had to step through the Save() function on the form to figure out how it was identifying whether the field is required or not, when I noticed that it just iterates over every control that has the required attribute (using JQuery, so I knew that there was hope that altering it at runtime could still work, rather than having it determined on load).
This has been a good brain exercise, even though the end result is so simple.
1 -
Alex_Marsh Premier Partner Advanced IT Monkey ✭✭✭>I finally got around to tidying the hodgepodge code I had above. Borrowing the original supplied code from @Tom_Hendricks I now have the following for a change form:
There's probably a few more optimisations that are needed (I would also like to generalise the function a bit more so it can be used on any form and accept the targeted fields but this has got me to a suitable point
app.custom.formTasks.add('ChangeRequest', null, function (formObj, viewModel) {<br> formObj.boundReady(function () {<br> var vm = pageForm.viewModel<br> var crclass = vm.Category.Name<br> if (crclass == "Minor"){<br> toggleFieldValidation(true, ["Description","Reason"]);<br> }<br> });<br>});<br> <br>function toggleFieldValidation(isRequired, fieldArray) {<br> console.log("function loaded")<br> // Iterate through all fields that are supplied to the function.<br> for (i = 0; i < fieldArray.length; i++) {<br> console.log(fieldArray[i]);<br> var addToLabelIfRequired = ' (Required)';<br> var field = $('[name="' + fieldArray[i] + '"]');<br> //console.log(field);<br> var fieldContainer = field.parent().parent();<br> var label = $('label[for="' + fieldArray[i] + '"');<br> //console.log(label)<br> <br> // " (Required)" is always the second <span> inside of the labels, so it can be targeted as the 2nd child, if it exists<br> var reqLabel = label.children('span:nth-child(2)').is(":empty");<br> //console.log(reqLabel);<br> <br> // If the field should be required and the label does not indicate this, add the appropriate text<br> if (isRequired && reqLabel) {<br> console.log("required")<br> label.append('<span>' + addToLabelIfRequired + '</span>');<br> }<br> // If the field should not be required and the label does not indicate this, remove the (Required) text from the label<br> if (!isRequired && !reqLabel) {<br> console.log('Removing label...');<br> reqLabel.remove();<br> }<br> <br> // Set the form field in accordance with isRequired<br> if (isRequired) {<br> console.log("required set")<br> field.prop('required', true);<br> fieldContainer.prop('required', true);<br> }<br> else {<br> field.removeAttr('required');<br> fieldContainer.removeAttr('required');<br> }<br> }<br>}
5
Answers
This enters the world of custom java script that can be added to the Custom.js file in the Custom Space folder.
You would have to add an evaluation function that would be triggered by the Lose Focus event for a control that you want to check. For example: If you wanted to make the Affect CI field required if someone chooses "Hardware fault" as the category then you would have a custom java script that would trigger when the Category drop down list "Loses Focus" (Users selects it then tabs away or clicks on another control)
You would then have the code look for the rules you want (Category Like "Hardware *") then run the code to add the required tag to the Affected CI control.
I'm no guru of Java Script and don't have a handy example.... Sorry.
You can either set the items as required in the form and then remove it under certain circumstances or don't make it required and set the attribute.
To remove:
To add:
$("elementselectors").prop('required', true);
You can trigger these events off of many different items with JS, as an example, when a kendo dropdown changes you can run a function to check the value:
@Brett_Moffett, I am decent with JS and setting up the events I need, etc., but was not sure where the property lived or how to access it--whether there was a Cireson object property to change, if it was in the Kendo control, etc. I did not phrase my question as well as I could have, I think!
@Cory_Bowe, I think you just cleared it up for me. Just one follow-up question: I see that you are not declaring your element as a kendo control (e.g., $('elementselectors').data('kendoControlOfSomeKind').removeAttr('required');), so this works against your plain vanilla DOM elements, right?
I am about to give this a whirl. I knew that I was probably staring right at the solution and just not seeing it for whatever reason, so I greatly appreciate the nudge!
Edit: I misread your statement, it should be the plain vanilla DOM elements, correct.
I can remove the "Required" attribute and change the label text, but the form will not save if the field was Required at load time. The opposite is true too. I can make the field "look" required, but the form will save if it is empty, as long as it wasn't required when the form loaded.
I think we still have part of the answer--how to change the appearance of the form--but I need the behavior to change too. If I find the answer I will post it here, but perhaps someone already knows...
I believe it depends on the type of element that you are trying to set required, ie textarea vs dropdown. If the element has a paired hidden input field you also need to control the required attribute on it.
I'm not sure what piece isn't working for you, but you could try this instead of the .prop method:
You are correct that for some Kendo controls there is a second, hidden element somewhere on the page that is also tied to the control, such as the dropdown list that appears when you begin searching for a user in an AutoComplete control. It is a couple DIVs with a UL list inside. However, none of these elements have a "required" property to set or remove, like the input element does.
@Cory_Bowe, have you been able to get this to work with a different type of control, perhaps? Or even better, with this one? I can successfully add/remove the "required" attribute from all applicable DOM elements, but it has zero effect on whether the field is validated on save or not. I am clearly missing something and I am hoping that it is something you have not missed.
I personally like to work from required to not, as its easier to just get all items tagged with required, hang them off jQuery so they persist outside of that script execution and then to add them back I'd just dump required back on with:
$.divTechReviewRequireds.attr('required', true);
This code did not work, however. The attribute is removed, but the form still cannot be saved until a value is entered into the field. The form validation does not see that the field is no longer required, so something has been missed somewhere. I feel like I have looked in every possible place, but clearly I have not.
Keeping with my example, $('input[name="RequestedWorkItem"]').parent().parent().removeAttr('required') will take care of it, after it has also been removed from the input element itself. I have yet to test this with other controls to see if they have different placement of the attribute, which would cause me to write this differently. The label was already taken care of near the top of this thread.
I had to step through the Save() function on the form to figure out how it was identifying whether the field is required or not, when I noticed that it just iterates over every control that has the required attribute (using JQuery, so I knew that there was hope that altering it at runtime could still work, rather than having it determined on load).
This has been a good brain exercise, even though the end result is so simple.
The example I wrote above is against a (nearly) out-of-box Incident form.
If you have the following code in your custom.js (make sure it only fires for the correct type of form, etc.) it will change the affected user field from required (as it is defined in my incident.js file) to optional:
"RequestedWorkItem" is the name of the Affected user relationship object. More importantly to this example, that is the property that the field is bound to, and also the value of the "name" attribute.
If you wanted to make the assignee field conditional on completion of the first activity, that would look something like:
Note that for fields that are not userpickers like my two examples, .parent().parent() in the middle of that statement may not be correct. It all depends on how the INPUT tag is nested and/or its relationship to the DIV tag with the "required" attribute.
There may be a more elegant way of accomplishing this that does not require counting div tags, of course.
app.custom.formTasks.add('Incident', null, function (formObj, viewModel) {
The code in this thread does not remove the "(Required)" text in the field label. You would need to add another line to do that. Here is an example function that puts it all together:
What I have noticed is that the ('span:nth-child(2)' is always returning a value of 1. After examining the incident form it seems that the <span></span> is always there whether or not the field is required. Does anyone know of a way to get the value of the field and to only remove if the contents contain 'is required'?
with some help from @Konstantin_Slavin-Bo and @Tom_Hendricks I've managed to sort the following:
This will enable the specified fields when loading the incident form if the priority <=3 and remove them if not. If the form loads with a priority < 3 and it gets changed the specified fields will enable.
As mentioned before my JS is pretty ropey and the adding " (Required)" has been a bit of a fudge seeing as the class is now there permanently regardless of whether the value is there or not, meaning I've had to go down another child layer. I'll have to go through the various scripts to see how the (Required) gets added to the second child as this will duplicate the span if a field is already set to required
There's probably a few more optimisations that are needed (I would also like to generalise the function a bit more so it can be used on any form and accept the targeted fields but this has got me to a suitable point