API help committing work item updates
My company would like to have the activities of a CR auto-populate to High priority if High priority is chosen in the General tab. I figured it wasn't too hard, and I feel like I'm pretty close to getting it, but I'm definitely missing something.
Would someone mind taking a look at this code and see if they can determine why the commit of the new data doesn't take effect? Displaying the activity in the console at the end of the script shows that the activity has the priority set as I wanted, but the commit never displays in the activity, even after saving and reloading the form. No errors in the console after the commit either.
Apologies for the mix of jquery and JS, I'm learning little by little. The for loop in the first section starts at 1 because the first activity in our templates is just a formatting runbook. Also, I have tried setting the newData.Activity.Priority as an array before committing, and that didn't seem to get it either.
Best Answers
-
Geoff_Ross Cireson Consultant O.G.Hi Raymond,
This is excellent work. In fact, its a bit too excellent, its far more complex than it needs to be. This would be ideal if you wanted to perform this function as a standalone task elsewhere in the portal or on the web but if you are already on the CR page, then the first half of this is done for you.
You can access the whole WorkItem object if you are on a WorkItem page with pageForm.viewModel This saves having to do the first call to GetProjection
You still need to set your values and then commit and that it is pretty good too. You could look into the jQuery each function to replace that for loop. Also, you only need to set the Id value for the Priority.
As for why its not committing, i suspect its the way you are setting newData as a copy of data. The way JavaScript works is it will only create a reference to the original object and then when you set values in it, you are in fact updating the original object too.
The commit API works by comparing the original to current, seeing what has changed and sending those changes to the SCSM Server so if you have changed both original and current, nothing will get sent to the SCSM server.
There's a handy way to actually copy an object, rather than make a reference to it which is to convert it to a string and back again.var y = JSON.parse(JSON.stringify(x))
Also I switched 'let' to 'var' for IE 11 support in case anyone out there still needs this.
Putting all this together and the following should work:var data = pageForm.viewModel; var newData = JSON.parse(JSON.stringify(data)); var activityCount = newData.Activity.length; for (var i = 1; i < activityCount; i++) { newData.Activity[i].Priority.Id = "32ee0157-fdc5-67c4-7971-c6b1fe8dfc66"; } var strData = { "formJson":{ "current": newData, "original": data } }; // Save Activities as High Priority $.ajax({ type: 'POST', url: '/api/V3/Projection/Commit', data: JSON.stringify(strData), contentType: "application/json", dataType: 'json', success: function() { console.log('done'); }, });
Nice work though, really close.
Geoff7 -
Jeff_Lang Customer Ninja IT Monkey ✭✭✭✭I agree doing it in the pageForm.viewModel is best, but just doing a single loop through the activities will not get them all if you have parallel or sequential activities with other activities in side them (we found out this the hard way when we first tried it.)it may be best to do something more like this to catch any of those instances where there are activities inside activities
var data = pageForm.viewModel;<br><br>function loopActivities(act) {<br> for (var i = 0; i < act.length; i++) {<br> act[i].Priority.Id = "32ee0157-fdc5-67c4-7971-c6b1fe8dfc66";<br> if (act[i].Activity.length > 0) { loopActivities(act[i].Activity}<br> }<br>}<br><br>if (data.Activity.length > 0) { loopActivities(data.Activity} }<br><br>var newData = JSON.parse(JSON.stringify(data));<br><br>var strData = { "formJson":{ "current": newData, "original": data } };<br>// Save Activities as High Priority<br>$.ajax({<br> type: 'POST',<br> url: '/api/V3/Projection/Commit',<br> data: JSON.stringify(strData),<br> contentType: "application/json",<br> dataType: 'json',<br> success: function() {<br> console.log('done');<br> },<br>});
although if doing this from the page itself, you could remove everything from</code><code>var newData = JSON.parse(JSON.stringify(data));
and down, then update the viewModel directly, and have it click the save or apply button on the page to save it
6 -
Geoff_Ross Cireson Consultant O.G.Hi Raymond.
Ahh, in all this above, I didn't think to check that Id you had there. That is the enumeration Id for High on a Change Request. You need the Id for High on an Activity. Different list = Different Id.
Try b2968b97-8f66-ee5e-84ec-f435fa6855445
Answers
This is excellent work. In fact, its a bit too excellent, its far more complex than it needs to be. This would be ideal if you wanted to perform this function as a standalone task elsewhere in the portal or on the web but if you are already on the CR page, then the first half of this is done for you.
You can access the whole WorkItem object if you are on a WorkItem page with pageForm.viewModel This saves having to do the first call to GetProjection
You still need to set your values and then commit and that it is pretty good too. You could look into the jQuery each function to replace that for loop. Also, you only need to set the Id value for the Priority.
As for why its not committing, i suspect its the way you are setting newData as a copy of data. The way JavaScript works is it will only create a reference to the original object and then when you set values in it, you are in fact updating the original object too.
The commit API works by comparing the original to current, seeing what has changed and sending those changes to the SCSM Server so if you have changed both original and current, nothing will get sent to the SCSM server.
There's a handy way to actually copy an object, rather than make a reference to it which is to convert it to a string and back again.
Also I switched 'let' to 'var' for IE 11 support in case anyone out there still needs this.
Putting all this together and the following should work:
Nice work though, really close.
Geoff
I took the suggestions back to my script. I copied what Geoff sent exactly as shown in his post. Everything looked as if it was going to work, but the commit didn't take. I logged out the data and newData variables to see before the commit, and the priority was updated for the "current" json, so I thought that was going to do it.
@Jeff_Langyou're right about the PA issue, I would've definitely run into that pretty quick, so I will certainly need to update my code. I will be the first to admit I'm probably not doing it right, but when trying to get the form to update directly within the form, I'm not having any luck, and getting json errors. Perhaps you're saying to just manipulate the form without using the API, which I haven't tried yet.
I'm using a similar process for updating items from the grid itself, such as directly assigning items from the Team Work view, so it's not the first time I've used the commit API, and I was hoping I could handle this. At least I didn't make any promises to management. If you guys have any more suggestions, they're welcome, but I'll definitely keep at it as well, as it can't hurt to keep learning!
I might have something else that could work, let me dig it out.
Again, it only works when you are on the actual WorkItem page, but that is basically the method that gets called when you click apply.
I don't know if this helps, but as a test, instead of priority, I changed the description of an activity, using the original script and that worked. Can it be that the priority field isn't being handled properly in the script?
Ahh, in all this above, I didn't think to check that Id you had there. That is the enumeration Id for High on a Change Request. You need the Id for High on an Activity. Different list = Different Id.
Try b2968b97-8f66-ee5e-84ec-f435fa685544
Thanks again for the help!
If anyone is interested, here's the current code:
app.custom.formTasks.add('ChangeRequest', null, function (formObj, viewModel) {
//Get the Priority at page load
//Watch if the user changes the Priority of the CR
const observer = new MutationObserver(function (mutations) {
//Find the new priority of the CR
//If the new value is different from the starting value, trigger the function
//In my environment, I have another script that sets MA fields to required, this clears it in order to apply changes
//Change the priority on the activity forms
const pageElement = document.getElementById('main_wrapper');
//Find the Id value for an activity Priority
//Set the Priority Id on the activities
//If PA, set the Priority Id for the activities within
//Apply the changes