It's all about the answers!

Ask a question

EWM/RTC Javascript attribute customization - does return value need to be the last line in script?


Becky McDermott (921140) | asked Dec 06 '23, 4:16 p.m.

 I had a "Calculated Value" script to set the value of a Custom Attribute.  This script had worked for a long time but suddenly started being flakey under 7.0.2 (worked sometimes and sometimes it didn't).  


I started playing with it in our DEVELOPMENT environment (adding some console.log statements) and discovered that it wouldn't set the custom attribute at all.  I could tell from the browser's "Development Tools"/"Console" and my "console.log" that the script was being invoked/executed but the value would never be updated.

I decided to take out the try/catch (originally had a try/catch block).  When I took out the try catch such that the last line in the script was the return value, the script worked/updated the custom value.

Are try/catch blocks forbidden in calculated values?

Script before (wouldn't update value):
dojo.provide("com.example.storyPointsLastModified");
dojo.require("com.ibm.team.workitem.api.common.WorkItemAttributes");
 
 (function() {
    dojo.declare("com.example.storyPointsLastModified", null, {
 
    getValue: function(attribute, workItem, configuration) {
 
        try {
// test
var lastModifiedDate = new Date();
var lastModifiedDateString = dojo.date.stamp.toISOString(lastModifiedDate, {milliseconds:true, zulu:true});
var txt = "The date story points were modified was:  " + lastModifiedDateString;
console.log(txt);
return lastModifiedDateString;
        }
        catch(err) {
            var txt; 
            txt="There was an error on this page.\n\n";
            txt+="Error description: " + err.message + "\n\n";
            txt+="Click OK to continue.\n\n";
            if (typeof window !== "undefined") {
               window.alert(txt); 
            }
        }
    }
    });
})();

Script after (successfully updates value):
dojo.provide("com.example.storyPointsLastModified");
dojo.require("com.ibm.team.workitem.api.common.WorkItemAttributes");
 
 (function() {
    dojo.declare("com.example.storyPointsLastModified", null, {
 
    getValue: function(attribute, workItem, configuration) {
var lastModifiedDate = new Date();
var lastModifiedDateString = dojo.date.stamp.toISOString(lastModifiedDate, {milliseconds:true, zulu:true});
var txt = "The date story points were modified was:  " + lastModifiedDateString;
console.log(txt);
return lastModifiedDateString;
    }
    });
})();

Accepted answer


permanent link
Ralph Schoon (63.2k33646) | answered Dec 07 '23, 2:10 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER
  1.  As far as I am aware, you can not use window alert. My understanding is, the Javascript is run in its own engine and has no connection to the web UI.
  2. You can use console.log. The log output goes into the eclipse workspace log.
  3. Calculated values and the other attribute customization provider are defining a function. You have to always return a value, otherwise the interface contract is broken and you do not get the correct behavior. In your case, if you try/catch you still have to return a valid value e.g. you can return the original value.
Becky McDermott selected this answer as the correct answer

Comments
Davyd Norris commented Dec 07 '23, 6:02 p.m. | edited Dec 07 '23, 6:08 p.m.

This is not quite correct:

 - window.alert will work in the web UI but will throw an exception in the Eclipse UI and on the server. Since Becky's code checks for a valid window object before using it, this is all legal and will not cause problems.
 - console.log will work in all three places. In the web UI it writes to the console in the developer tools for the browser, on the server it writes into the log file
 - in Javascript, by default, if a function's execution doesn't end at a return statement, or if the return keyword doesn't have an expression after it, then the return value is 'undefined'. The return statement simply allows you to return an arbitrary value from the function. 'undefined' would be parsed as a null or zero in the attribute code


Ralph Schoon commented Dec 08 '23, 3:02 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER

It has been stated by the developers in the past, that you must not use window.alert or similar capabilities. 

Attribute customization can also run in the Eclipse client, where window.alert is not available and does not work. 

My experience so far is, that not returning a valid value is not giving a good experience, so I make sure I know what is returned. This is especially true, because the return value is later processed in the Java SDK. How do you create an integer value from an undefined return value?


Davyd Norris commented Dec 08 '23, 6:51 p.m.
Hi Ralph,

You can use Web UI only capabilities as long as they are properly protected - Becky's code example is doing just that. If you reread my response above this will be clearer - there are three places where the code runs: the Web UI, the Eclipse UI and the server. Each of these places has elements not present in the others, but you can write code that uses them if properly protected as above.

You do not create an integer from an undefined value, you must test the return and respond appropriately. It appears the internal code is doing that -it would need to do that even if you explicitly returned a value, as even something like parseInt() will return NaN for any input that can't be converted into an integer

3 other answers



permanent link
Becky McDermott (921140) | answered Dec 07 '23, 6:21 p.m.

 @DavydNorris

 In my DEV environment, I couldn't get the custom attribute to update at all.  The script was being invoked because I saw the "console.log" output in the browser tools but after saving the work item, the custom attribute would just appear as "None" in query output.

That's when I got the idea to completely take out the catch and observed that it started working.  It is my understanding that;
 if (typeof window !== "undefined") {
    window.alert(txt); 
}

only runs "window.alert" on the client.

 I know I don't really need the try/catch since the value is being set to the current date time.  It may make sense to just remove the try/catch all together.  

In our PRODUCTION environment, my users were complaining that the value does get set "sometimes" so maybe your theories are correct.  I was planning to update the script in PROD this weekend so I think I will take out the try/catch all together.  Will see if my users quit reporting the problem.

Thank you for all your great insights/suggestions.


Comments
1
Davyd Norris commented Dec 07 '23, 11:07 p.m.
Yes wrapping the window object like that will stop it from throwing an exception in the Eclipse and server environments - that bit is exactly the right thing to do.

The fact that the output is appearing as None would seem to indicate that the catch block is being triggered and an 'undefined' value is being returned by default, which is then being parsed into a nothing result.

Do you have access to your server ccm.log file? That will show what's happening on the server side. Many of these customisations run both in the client and on the server, and that's where it might be working fine on the client but then errors on the server and you get no value. The server log will show you that

permanent link
Becky McDermott (921140) | answered Dec 07 '23, 1:06 p.m.

 @Ralph Schoon:


 Thank you for your explanation.  It was very helpful.  I was finally able to get it working as desired by adding the return of the original value in the catch as you suggested.  If I uncomment the "throw new Error" line and step through the debugger (setting ?debug=true and using the browser's developer tools to load the script), I can see that the "window.alert" does display a diaglog box which is good.

The final script looks like:
dojo.provide("com.example.storyPointsLastModified");
dojo.require("com.ibm.team.workitem.api.common.WorkItemAttributes");
 
 (function() {
    dojo.declare("com.example.storyPointsLastModified", null, {
 
    getValue: function(attribute, workItem, configuration) {
// Get the current value of the custom attribute (used in "catch" path)
var storyPointsModifiedCur = workItem.getValue("storyPointsLastModified");
     try {
var lastModifiedDate = new Date();
var lastModifiedDateString = dojo.date.stamp.toISOString(lastModifiedDate, {milliseconds:true, zulu:true});
var storypointsactual = parseInt(workItem.getValue("com.ibm.team.apt.attribute.complexity"), 10);
var txt = "The date story points were modified was:  " + lastModifiedDateString;
console.log(txt);
//throw new Error('Cannot update storyPointsLastModifiedAttribute');
return lastModifiedDateString;
}
catch(err) {
            var txt; 
            txt="There was an error on this page (Attribute:  storyPointsLastModified was NOT updated).\n\n";
            txt+="Error description: " + err.message + "\n\n";
            txt+="Click OK to continue.\n\n";
            if (typeof window !== "undefined") {
               window.alert(txt); 
            }
            return storyPointsModifiedCur;
        }
    }
    });
})();

Thank you for your response.


Comments
Davyd Norris commented Dec 07 '23, 6:05 p.m. | edited Dec 07 '23, 6:06 p.m.
See my comment against Ralph's reply. If adding a formal return statement to your catch block gives you a value then that means your catch block is being triggered, possibly by the window.alert function trying to run on the server but possibly due to something else. 

Leaving out a return is perfectly legal Javascript, and will mean the function returns the Javascript default value 'undefined', which will then be parsed by the attribute's internal code as a null or zero and so you'll get no value displayed.

Becky McDermott commented Dec 07 '23, 6:20 p.m.

I couldn't fit the response in the character limit so see my answer below.


permanent link
Davyd Norris (2.4k217) | answered Dec 06 '23, 4:44 p.m.
No you can return at any time. 

There are a couple of things to check:
 - you have a console log statement in your try but not your catch. While I can't see that your script would throw an error it may be worth checking that catch isn't being invoked, because you return nothing inside it
 - I'm not sure you even need a try/catch here. What were you wrapping that might need exception protection?
 - having said that, try/catch should work just fine as it's standard Javascript

Comments
Becky McDermott commented Dec 06 '23, 6:07 p.m.

I had tried it with a console.log in the catch and it never entered the catch.

I agree that what I'm doing doesn't require a try/catch (I had just modeled the script after another one that had a try/catch).

I would have thought the script would be standard but it plainly doesn't work in any of my 7.0.2 environments if I have the try/catch.

I have an open support case open with IBM but the support engineer is off until Monday.  I will see what he says.

Thank you


Davyd Norris commented Dec 06 '23, 7:53 p.m.
So are you trying this specific script above and it's not behaving, or the original?

Due to the single threaded nature of Javascript, if you are doing anything in your calculated field that is pseudo asynchronous in nature, the function may be returning before the value calculation has completed, and so the field will end up with nothing.

It would be really interesting to pepper your code with log statements and see the order they appear in. In particular, add a log statement at the end of the function outside the try catch, and then inside the try. Also add a return at the end as well as in the try and return an obvious dummy value. If the dummy appears and not the one returned by the try then you have something race condition related going on

Your answer


Register or to post your answer.


Dashboards and work items are no longer publicly available, so some links may be invalid. We now provide similar information through other means. Learn more here.