It's all about the answers!

Ask a question

How to set attributes before a workItemProxy.storeWorkItem() call? (RTC/EWM) (javascript)


Kevin Johnson (116) | asked Apr 07 '21, 10:25 a.m.
Hello,

We have JavaScript code that creates a new work item but we are unable to set any attribute values before the creation. Our current workaround is to create the "empty" work item and then with JavaScript modify the work item. Ideally, we want to set the attribute values before the creation.

This posted forum question from 2015 shows an example in how you would do that above in (maybe) RTC 5.x:

But with EWM 7.0 this type of code does not work for us - it does not set the Summary value:

var newProxy = WorkItemProxyFactory.getWorkItemProxy({createIfNeeded: true});
newProxy.initialize(...);
newProxy.object.attributes.summary.content = "Testing 123";     // this does not work for us
newProxy.storeWorkItem(...);

And this appears in console debug output:
Legacy bindings should not convert new work items
ItemProxy error notifying: attributes,applications. The page may have been unloaded.

The attribute is created but Summary is not set.

Please advise on how to set attribute before (or upon) creation.

Thanks,
Kevin

Comments
Ralph Schoon commented Apr 07 '21, 2:48 p.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER
As far as I am concerned that API is not documented anywhere and therefore considered an internal API. I have stated this in several questions where this has been discussed. Internal API can change without notice and can break users code.

The only hope here is that someone has figured out how to use this API.  

Kevin Johnson commented Apr 09 '21, 4:08 p.m.
Hello Ralph,

Thank you. Glad to see Davyd responded below...

-Kevin

2 answers



permanent link
Davyd Norris (2.1k217) | answered Apr 07 '21, 7:08 p.m.
edited Apr 07 '21, 8:43 p.m.
As Ralph says above, this is an undocumented internal API and likely to change, but I had to do this for a client and this code works in 6.x and appears to still work in 7.x but I need to more thoroughly test in the later releases.

This code is used to create a child review task on a work item at a certain point in the workflow, and assign a SME and due date, so it shows creating the item, setting various built in and custom attributes, and creating parent/child link.

Because of the callbacks, it's a bit difficult to read but basically a proxy is created for a new work item, then the settings and values for the content are set up in a params object, including code that sets the values and saves the work item if it's successfully initialised. Finally the initialise is called with the params to kick off the whole create and save:

  var WorkItemAttributes = com.ibm.team.workitem.api.common.WorkItemAttributes;
  var WorkItemProxyFactory = com.ibm.team.workitem.web.cache.internal.WorkItemProxyFactory;

  var valueObject = function(workItem, attr, val) {
    var vo = {
      attributeId : attr,
      path : [ 'attributes', attr, workItem._getIdSegment(attr) ],
      value : val
    };
    return vo;
  };

  var addReview = function(workItem, category, owner) {
    console.log('addReview');
    var newProxy = WorkItemProxyFactory.getWorkItemProxy({
      id : -1,
      createIfNeeded : true,
      doNotGetFromCache : true,
      doNotCache : true
    });

    var params = {
      newWorkItem : true,
      type : "review",
      fetchEditorPresentation : false,
      fetchInlinePresentation : false,
      projectAreaItemId : workItem.getValue(WorkItemAttributes.PROJECT_AREA),
      onSuccess : function() {
        console.log('WI Initialisation Success');
        newProxy.setValue(valueObject(workItem, WorkItemAttributes.SUMMARY, category.name + ': '
                + workItem.getValue(WorkItemAttributes.SUMMARY)));
        newProxy.setValue(valueObject(workItem, 'cpfSummary', workItem.getValue(WorkItemAttributes.SUMMARY)));
        newProxy.setValue(valueObject(workItem, WorkItemAttributes.OWNER, owner));
        newProxy.setValue(valueObject(workItem, WorkItemAttributes.FILED_AGAINST, category.id));
        var dueDate = workItem.getValue(WorkItemAttributes.DUE_DATE);
        if (dueDate === null) {
          dueDate = new Date();
          dueDate = dueDate.setDate(dueDate.getDate() + 2);
        }
        newProxy.setValue(valueObject(workItem, WorkItemAttributes.DUE_DATE, dueDate));

        var linkparam = {
          isNew : true,
          addLinkType : "com.ibm.team.workitem.linktype.parentworkitem",
          addLinkIsSource : "false",
          addLinkedProjectAreaItemId : workItem.getValue(WorkItemAttributes.PROJECT_AREA),
          addLinkedItemId : workItem.getWorkItemItemId()
        };
        newProxy.addLinkTarget(linkparam);

        var saveparam = {
          self : this,
          operationMsg : "Saving",
          applyDelta : true,
          onSuccess : function(param) {
            console.log('WI Save Success');
          },
          onError : function(err) {
            console.log('WI Save Error');
            console.log(err);
          }
        };
        newProxy.storeWorkItem(saveparam);
      },
      onError : function(err) {
        console.log('WI Initialise Error');
        console.log(err);
      }
    };
    newProxy.initialize(params);
  };


Comments
Kevin Johnson commented Apr 09 '21, 4:07 p.m.
Hello Davyd,

Thank you. This looks promising.

Within "var params = {... }" it looks like variable workItem is the parent work item of the child review task. You call "newProxy.setValue(valueObject(workItem,...)" a few times. Is the call to valueObject getting the value of the parent work item attribute and then you are copying/setting the attribute of the child review task with the parent's value?

I'm trying to figure out what workItem._getIdSegment(attr) does. If I do not have a parent WI to copy the attribute from then how would I change valueObject/

Thanks!

-Kevin

Davyd Norris commented Apr 09 '21, 6:36 p.m.

Ran out of space in the comment - see below


permanent link
Davyd Norris (2.1k217) | answered Apr 09 '21, 6:35 p.m.
The valueObject function simply converts an attribute or link into the required internal format the work item uses during storage - it's a Java script object that consists of the attribute name, value and its 'path' which is the internal hierarchy its stored under.

The _getIdSegment() function returns this path.

As mentioned before, this snippet was created to create a SME Review child work item at a particular point in the overall workflow of the parent. The SME review data was derived completely from the parent's content so you're correct, but you could use any data you like, passed in any way you like. In this example:

newProxy.setValue(valueObject(workItem, WorkItemAttributes.SUMMARY, category.name + ': ' + workItem.getValue(WorkItemAttributes.SUMMARY)));

sets the Review's Summary to a string made up of the review category (category is externally derived - it's an object, so this is one example of passing in your own data) plus the parent's Summary attribute

newProxy.setValue(valueObject(workItem, 'cpfSummary', workItem.getValue(WorkItemAttributes.SUMMARY)));

sets a custom attribute to the parent's Summary

newProxy.setValue(valueObject(workItem, WorkItemAttributes.OWNER, owner));

sets the Review's Owner attribute to the owner variable, which is passed in

newProxy.setValue(valueObject(workItem, WorkItemAttributes.FILED_AGAINST, category.id));

sets the Filed Against attribute to the category passed in

var dueDate = workItem.getValue(WorkItemAttributes.DUE_DATE);
        if (dueDate === null) {
          dueDate = new Date();
          dueDate = dueDate.setDate(dueDate.getDate() + 2);
        }
        newProxy.setValue(valueObject(workItem, WorkItemAttributes.DUE_DATE, dueDate));

sets the Due Date of the Review to either be the same as the parent work item, or two days from the current date if no due date was set on the parent

var linkparam = {
          isNew : true,
          addLinkType : "com.ibm.team.workitem.linktype.parentworkitem",
          addLinkIsSource : "false",
          addLinkedProjectAreaItemId : workItem.getValue(WorkItemAttributes.PROJECT_AREA),
          addLinkedItemId : workItem.getWorkItemItemId()
        };
        newProxy.addLinkTarget(linkparam);

creates and adds a new Parent link back up to the parent work item


Comments
Kevin Johnson commented Apr 14 '21, 9:35 p.m.
Davyd,

Thank you. One more question.

What is variable workItem? For example:
newProxy.setValue(valueObject( workItem, WorkItemAttributes.OWNER, owner ));

When I try workItem._getIdSegment(attr) I get on my console: _getIdSegment is not a function. I cannot find _getIdSegment anywhere. I was thinking workItem is this.workItem while in the context of my JavaScript.

Davyd Norris commented Apr 14 '21, 10:17 p.m.
This function runs in the context of an attribute customisation or condition, and every one of those functions is passed in a parameter called workitem, which is the current work item that has triggered the function

Kevin Johnson commented Apr 14 '21, 10:56 p.m.
Davyd,

Yes, in my attribute presentation customization code I am grabbing parameters.workItem from my constructor. And parameters.workItem has all my attributes, id, itemId, locationUri, etc. but no function called _getIdSegment().

I am running EWM 7.0.1.

-Kevin

Ralph Schoon commented Apr 15 '21, 2:18 a.m. | edited Apr 15 '21, 2:18 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER

Carefully read the answer Davyd gave. The parameter workItem is available in JavaScript (or Java) Attribute Customization see https://jazz.net/wiki/bin/view/Main/AttributeCustomization. If you are talking about a custom editor presentation, that information might or might not be available or available in a different way. 

Your answer


Register or to post your answer.