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: Changes made to pickers are not always synchronized to dropdown #166

Open FlowIT-JIT opened 1 year ago

FlowIT-JIT commented 1 year ago

See the following example: https://jsfiddle.net/9zca6kf1/1/

Fit.Events.OnReady(function()
{
    // Create DropDown
    var 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.Width(400);
    dd.DropDownMaxHeight(150);
    dd.OnRequest(function(sender, eventArgs)
    {
        eventArgs.Request.SetParameter("Parent", eventArgs.Node && eventArgs.Node.Value() || "");
    });
    dd.Render(document.querySelector("#DropDownContainer"));

    var btn = new Fit.Controls.Button();
    btn.Type(Fit.Controls.ButtonType.Primary);
    btn.Title("Select TreeView node programmatically");
    btn.OnClick(function()
    {
        var tv = dd.GetTreeView();
        tv.Reload(false, function(sender)
        {
            firstNode = tv.GetChildren()[0];
            firstNode.Selected(true); // Does not synchronize to DropDown
            console.log("Node '" + firstNode.Title() + "' selected: " + firstNode.Selected());
        })
    });
    btn.Render(document.querySelector("#ButtonContainer"));

    window.dd = dd;
    window.btn = btn;
});

Click the button to load TreeView data and select the first node. Do NOT open the DropDown control first! Notice how the selection is not reflected in the DropDown control. Now open the DropDown - this results in TreeView being updated with the selection from the DropDown control (which is empty), so the selection in the TreeView is lost.

The same problem might occur if data returned from the server contain nodes that are preselected. These selections will also not propagate to the DropDown control, and they will be lost when DropDown control is opened.

If we open the DropDown control first, before clicking the button, synchronization works as expected.

This is a minor bug since we would normally use the DropDown instance to change selection: dd.AddSelection("Title goes here", "Unique Value")

FlowIT-JIT commented 1 year ago

The problem is caused by the fact that synchronization events are wired when WSDropDown assigns a picker for the first time using e.g. me.SetPicker(tree). This happens when the pull down menu is opened. Therefore any interaction with the picker controls prior to opening the pull down menu will not propagate back to the DropDown control.

A quick and dirty solution to this would be to call SetPicker(..) in the WSDropDown's constructor for each picker control to ensure wiring of events like demonstrated below, but this introduces a new bug; the TreeView will load data when rooted, and we don't want data to load unless needed!

image

The solution above will cause TreeView to become rooted and therefore load data:

image

We would need to move the logic responsible for wiring synchronization events in SetPicker(..) so it can be used without rooting the picker in the DOM.

FlowIT-JIT commented 1 year ago

The issue has now been resolved.

image

However notice that changes to selection state only propagates to the WSDropDown control if nodes actually exist in the WSTreeView instance. Setting a value or node selection on the WSTreeView instance using Value(..) or SetNodeSelection(..) will not result in this change propagating to the WSDropDown control if the nodes specified does not actually exist (e.g. not loaded yet), but are merely preselections. So make sure data is loaded first:

wsDropDown.GetTreeView().EnsureData(function(sender) { /* Manipulate selection state here */ });

To be determined: Should selection of non-existing nodes be synchronized to DropDown control when assigned via picker control? It works when assigned via DropDown control.