UPDATE! The community will be go into read-only on April 19, 8am Pacific in preparation for migration on April 21. Read more.
UPDATE! The community will be go into read-only on April 19, 8am Pacific in preparation for migration on April 21.Read more.
Absent Member.
Absent Member.
9107 views

How to get sub-relational AND dependednt fields update in JS?

This is a two-part questions, but related.
1. I have a single relational field on my primary table whose aux table has a multi-relational field. That field is a sub-relational field on the primary. In an AddChangeCallback or form action, the new value of the controlling single-relational field is available, but the sub-relational continues to report the old/original value.
2. Ditto for a dependent field.
Not until I submit/post the form does the new value get updated. Is there a way to trigger that update on the form so that sub-relational and/or dependencies are current?

As another follow-up, I tried SetFieldValue with the last arg as true, but that made no difference. What is the purpose of that argument? The doc says, "If this parameter is set to true, then setting the values causes
the change event to fire. If this parameter is set to false, then
the change event does not fire." but I can observe no effect either way. Please provide a better explanation of that argument and examples of how to use it effectively. Thanks.
0 Likes
17 Replies
Absent Member.
Absent Member.

Hey Steve,
Is your sub-relational field inside a control like a panel or expander and if so, does that control have some javascript or form action associated with it? I'm thinking that there is something else in the form preventing the refresh from happening because we have a lot of sub relational fields on our CMDB forms and they are refreshing properly when the parent relational field is changed. So, I'm guessing there is something else interfering. If not, you could always try putting your sub-relational field inside of a panel or something and then writing a javascript to refresh just that panel of the form when the parent field changes to test if that would force the update through. Just a thought.

-ryan
0 Likes
Absent Member.
Absent Member.

Two issues going on here:

1. A race condition on the change event - you are trying to get the value of the subrelational field when the driver field (single-relational) changes, but at that point the subrelational still has the old value. An AJAX call has been fired of to get the new subrelational, but it won't return for some (X) milliseconds _after_ the driving change event has already been called. The solution is to attach/detect when the AJAX call completes, _then_ you will have the new value available. I'll post a JS function below which helps with that.

2. A Bug on subrelational user fields where even after the value is changed by the AJAX in #1 above, the iValues are not updated, so it still keeps the internal ID(s) of the old subrelational value. The ID's are there in the AJAX response (APF Request) but they are being ignored. This was filed with support as DEF223363 and was closed as resolved in 10.1.4, though there is some question as to whether it was fixed on all transition forms, or just Submit.


Here is the helper function that I used to work around the race condition in #1. Call this as you would call an AddChangeCallback or AddClickCallback, passing it a function(){} that takes the action you'd like. I'll note that this is fairly ugly (doing it with a listener), but I wasn't able to find any clean way to hook into the APF_Request object and attach a true callback... perhaps someone with better JS chops could figure that out.


function AddAjaxLoadCallback(fnCallback)
// Adds a transient callback to the currently-executing AJAX request, allowing execution of scripts after sub-relational fields load
{
if (top && top.req) {
if (top.req.readyState == 4) {
if (top.req.status == 200) {
fnCallback();
};
} else { // AJAX request is in progress, create a listener
var ajaxListener = setInterval(function() {
if (top.req.readyState == 4) {
clearInterval(ajaxListener);
if (top.req.status == 200) {
fnCallback();
};
}
}, 100);
}
};
};
Absent Member.
Absent Member.

Hi Ryan,

First, before we get into the meat of the matter... Could you please post or email a JavaScript function that does what you said, "refresh just that panel of the form when the parent field changes." I have been looking to do this for another use case.

I believe this is a bug (or missing functionality) in SBM. Indeed, sub-relational fields will update/refresh in real-time on a transition form as long as it is a single value field. In my case, my sub-relational field is **multi-selection**. A single selection and a user sub-relational work fine. The annoying thing is, multi-fields can be subrelational, and the value is properly reflected on the state form, but only the initial value will ever show on the transition form.

Hoping that a Serena developer will publish some JavaScript I can plug in to fix this defect.

Thanks,
-Steve
0 Likes
Absent Member.
Absent Member.

I am also researching it currently...

I'm getting ready to test this out in a form action where changing one field calls this function. I had to pull the div id by inspecting the element in the browser. In my case it came back with "Section00ea88fd-5fac-4f1b-9d09-d0a856f1ae19". I'll let you know how it works.

0 Likes
Absent Member.
Absent Member.

Thanks Jeff,
Your code solves the problem for single value field types. Thanks. I can use that. Yet, multi-selection fields do not work regardless. Here is my complete code that calls your function. Feel free to comment or correct if you have any further suggestions.
Cheers

// TEST_PRODUCT is my parent/driving field. The 3 Product xxx are sub-relational.
// Product Customs is multi-selection; Product Single is single-selection; Product User is a single-user.
function onChangeParent()
{
var testproductraw = GetFieldValue("TEST_PRODUCT"); // Single-relational parent/driving field. This correctly retrieves the new value I just now selected.
var testproductmulti = GetMultiListValues("Product Customs"); // NoWorky: did not change in tandem.
var testproductsingle = GetFieldValue("Product Single"); // Not here yet--old value still retrieved.
var testproductuser = GetFieldValue("Product User"); // Not here yet--old value still retrieved.
AddAjaxLoadCallback(GetSubRelationalValues);
}
AddChangeCallback("TEST_PRODUCT", onChangeParent);

function GetSubRelationalValues()
{
// This gets called, so it appears your code is working as expected. Thanks for that!
// HOWEVER, the var value I get on the next line still contains the original value(s),
// not the new sub-relational value(s) associated with the new value of the parent.
var testproductmulti = GetMultiListValues("Product Customs"); // expected array: [Value1, Value2] -- NoWorky: still contains the original value.
var testproductsingle = GetFieldValue("Product Single"); // Works! Jeff Malin's AjaxLoadCallback to the rescue.
var testproductuser = GetFieldValue("Product User"); // Works! Jeff Malin's AjaxLoadCallback to the rescue.
}
AddChangeCallback("Product Customs", onChangeProductCustoms);
0 Likes
Absent Member.
Absent Member.

Steve,
This method works but I'm still having trouble getting it to function in the application correctly. That said, if you drop it into a widget and run it independently against a div that you define it works. So, I'm gonna keep playing with it to see if I can get it to function in the form the way I want but I figured I'd pass it on since my intended use may be different than yours.

function refreshPanel(){

var container = document.getElementById("a91030ec-a4de-4a68-a659-2a3d03ecec8a");
var content = container.innerHTML;
container.innerHTML= content;
}



I also tried using getElementsByName with the control name but that wasn't working at all for me. I'll pm you if I get any further with it.
0 Likes
Absent Member.
Absent Member.

Hi Ryan,
Haven't had a chance to experiment with your code as yet, but here is what I am hoping to do:
I have written js to open a jquery-ui modal on top of the state form and present a transition form. On OK, I do this craziness:
var view = getAeRootWindow(window);
view.SetFieldValue("RELEASE_FOUND_IN", GetFieldValue("RELEASE_FOUND_IN"));
...to update the values shown in the view, in place, without having to reload the entire state form. It actually works, but has some issues handling user errors and record locks.

But what I was hoping is that there is a better way. All the fields I am modifying in my transition form are contained in a single panel (expander, actually) on the state form. It would be sweet if I could simply call one function (like the one I think you are working on) to reload just the fields in that div--not the entire page.

The kicker is that I know John Hastings-Kimball has done exactly this. He is working on upgrading his mashup to Work Center, but I have not heard that he has this ready, as yet. I am hoping he will share the solution "any day now", but I don't know if that is coming very soon, or is a long way off. I have a schedule that requires me to solve this issue and upgrade to Work Center in early August. Hence, my hope that you or a Serena developer will post a solution.

I would be happy to share my modal dialog code, or anything else I might have. But it is not "production-worthy" yet.
0 Likes
Absent Member.
Absent Member.

Steve Dieckbrader wrote:
I have a schedule that requires me to solve this issue and upgrade to Work Center in early August.


Hi Steve - my understanding is that moving to Work Center will essentially solve this issue for you as all the transitions there open in Dialogs... or did I miss something?
0 Likes
Absent Member.
Absent Member.

Hi Jeff,
Well....yes. All view and transition forms are hosted within a Bootstrap modal window, but I can hardly call it a modal dialog. Technically it is, but functionally it is little different from displaying the view or formbody within the surrounding frame. To function as one would expect a modal to do, initiating an edit should pop up a smaller modal dialog, dim the state form beneath it, allow one to make edits to fields, click OK, dismiss the modal popup, and have their field changes immediately reflected in the state view without having to reload the entire state view.
This is the behavior that JHK demonstrated last December in a Serena-sponsored webinar I attended. I have this behavior mostly working, but with a few wrinkles. I would really, truly, love to work with a Serena developer to complete it. I think it would benefit all customers, and could become a truly exceptional feature. The only parts I have to get working are anomalous use cases: record lock failure, reloading change history, the stuff on the fringes. These could probably be solved by a Serena developer who knows your internals very easily. For me, it is a time-consuming process of inspecting the DOM using devtools and reverse engineering.
Consider that an offer and a proposal....
0 Likes
Fleet Admiral
Fleet Admiral

Jeff Malin wrote:

{snipsnip}

Here is the helper function that I used to work around the race condition in #1.


If you are doing JavaScript in SBM, you will eventually need Jeff's utility function. Greatest thing since sliced bagels. Thanks Jeff!
0 Likes
Absent Member.
Absent Member.

Thanks PT! This little guy does come in handy. You can actually chain it if you need to set multiple subrelationals... I have some apps where it's calling 3-levels deep !


Set value of Relational;
Add Ajax Load callback() {
Get Value of subrelational;
Set second Relational / Fire Change Event;
Add Ajax Load callback() {
Get value of second Subrelational;
Set value of third relational...;
};
};

... and so-forth.
0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.