Jemt / Fit.UI

Fit.UI is a JavaScript based UI framework built on Object Oriented principles
http://fitui.org
GNU Lesser General Public License v3.0
19 stars 7 forks source link

WSDropDown: ResetActionMenu() prevents Action Menu from updating to reflect current state #179

Closed FlowIT-JIT closed 1 year ago

FlowIT-JIT commented 1 year ago

See the following example: https://jsfiddle.net/sak91qdm/7/

Fit.Events.OnReady(function() {
  dd = new Fit.Controls.WSDropDown("WSDropDown1");
  dd.Url("https://fitui.org/demo/GetUsers.php");
  dd.JsonpCallback("JsonpCallback"); // Loading data from foreign domain
  dd.MultiSelectionMode(true);
  dd.Value("James Thomson=james@server.com;Hans Törp=hans@server.com");
  dd.Width(300);
  dd.DropDownMaxHeight(150);
  dd.InputEnabled(true);
  dd.UseActionMenu(true); // Show action menu initially
  dd.OnRequest(function(sender, eventArgs) {
    eventArgs.Request.SetParameter("NoCache", Fit.Data.CreateGuid());
    eventArgs.Request.SetParameter("Search", dd.GetInputValue());
  });
  dd.OnChange(function(sender) {
    // Make DropDown use TreeView when opened again.
    // If data is reloaded and no data is received
    // then ActionMenu will be used.
    // BUG: Calling ResetActionMenu() prevents action menu
    // from updating, so if we remove all selected items using the
    // Action Menu, then "Remove all selected" remains visible.
    dd.ResetActionMenu();
  });
  dd.Render(document.querySelector("#Control"));

  if (Fit.Browser.IsMobile())
    dd.Width(100, "%");
});

Remove the two selected items using the Action Menu.

image

Notice how "Remove all selected" is not removed as expected.

image

Take another example: https://jsfiddle.net/t0wukzm9/9/

var dd;
Fit.Events.OnReady(function() {
  dd = new Fit.Controls.WSDropDown("WSDropDown1");
  dd.Url("https://fitui.org/demo/GetUsers.php?empty=true");
  dd.JsonpCallback("JsonpCallback"); // Loading data from foreign domain
  dd.MultiSelectionMode(true);
  dd.Value("James Thomson=james@server.com;Hans Törp=hans@server.com");
  dd.Width(300);
  dd.DropDownMaxHeight(150);
  dd.InputEnabled(true);
  dd.OnChange(function(sender) {
    doSomethingAsync();
  });
  dd.Render(document.querySelector("#Control"));

  if (Fit.Browser.IsMobile())
    dd.Width(100, "%");
});

function doSomethingAsync() {
  setTimeout(function() {
    dd.Url(dd.Url().replace("?empty=true", ""));

    // Make DropDown use TreeView when opened again.
    // If data is reloaded and no data is received
    // then ActionMenu will be used.
    // BUG: ClearData() below should update Action Menu
    // so that "List with options is empty" is changed to
    // "Show available options" but it doesn't when
    // ResetActionMenu() is called first.
    dd.ResetActionMenu();

    // Reload data when needed. Unfortunately Action Menu
    // does not update as expected, so rather than showing
    // "Show available options" it remains stuck on
    // "List with options is empty" due to the call to
    // ResetActionMenu() above.
    dd.ClearData();
  }, 100);
}

In this example no data is initially received, so the Action Menu shows "List with options is empty" as expected. But once data is changed, we discard any existing data loaded, and therefore the Action Menu is expected to update and display "Show available options" - but it doesn't.

Remove an item using the Action Menu.

image

An async operation executes which clears data from the DropDown so it will reload when needed. This potentially makes data available so the Action Menu should be updated to display "Show available options", but instead it remains stuck with "List with options is empty".

Both problems are related to the use of ResetActionMenu() which we use to make the DropDown show the TreeView next time it is opened - and in our case this happens when the control's OnChange event fires.

Everything works as expected when the DropDown is closed when resetting the Action Menu and clearing loaded data since the DropDown control assumes the correct state when reopened, as this example demonstrates:

https://jsfiddle.net/o90jpe45/5/

Fit.Events.OnReady(function() {
  var dd = new Fit.Controls.WSDropDown("WSDropDown1");
  dd.Url("https://fitui.org/demo/GetUsers.php?empty=true");
  dd.JsonpCallback("JsonpCallback"); // Loading data from foreign domain
  dd.MultiSelectionMode(true);
  dd.Value("James Thomson=james@server.com;Hans Törp=hans@server.com");
  dd.Width(300);
  dd.DropDownMaxHeight(150);
  dd.InputEnabled(true);
  dd.Render(document.querySelector("#Controls"));

  var b = new Fit.Controls.Button();
  b.Title("Load new data");
  b.OnClick(function(sender) {
    // Make endpoint return data by removing ?empty=true
    dd.Url(dd.Url().replace("?empty=true", ""));

    // Make DropDown use TreeView when opened again.
    // If data is reloaded and no data is received
    // then ActionMenu will be used.
    dd.ResetActionMenu()

    // Reload data when DropDown is opened again.
    dd.ClearData();
  });
  b.Render(document.querySelector("#Controls"));

  if (Fit.Browser.IsMobile())
    dd.Width(100, "%");
});

But naturally we should be able to ensure that the DropDown prefers the TreeView control "later" by calling ResetActionMenu during the execution of OnChange, without causing the Action Menu to display incorrect state while the DropDown is open.

FlowIT-JIT commented 1 year ago

Fixed. Both examples are working now with Fit.UI 2.12.2: https://jsfiddle.net/kafq6n5j/ https://jsfiddle.net/txo8p952/