json-schema-form / angular-schema-form

Generate forms from a JSON schema, with AngularJS!
https://json-schema-form.github.io/angular-schema-form
MIT License
2.47k stars 653 forks source link

No way to know the source of onClick event in arrays/tabarrays #908

Open t27 opened 7 years ago

t27 commented 7 years ago

Enhancement/Bug

As a user/developer, when I have a "Button" form element inside an array/tabarray schema, and this button has an onClick handler, I should be able to access the active tab index, since the purpose of having a button inside the form would be to make tab specific changes.

Behaviour

Currently, there is no way to do so. When we click on the button from any of the tabs, the same handler is called. But there is not indication of the current state.

Investigations

I looked into the code and found the definition of the click triggerring code here

Now as a hack, I passed the scope as the third element in the handler. I was able to access the active tab array index in the 2nd parent's arrayIndex variable. (scope.$parent.$parent.arrayIndex). But obviously this change wouldn't be worth a PR since it exposes the scope. I also cant pass the array index directly since this hierarchy is specific to my use case. We probably need to devise a generic way to provide the active indices.

scope.buttonClick = function($event, form) {
          if (angular.isFunction(form.onClick)) {
            form.onClick($event, form, scope);
          } else if (angular.isString(form.onClick)) {
          ...
        };

Is there any better way to access the current index of the source tab which triggers the event?

@json-schema-form/angular-schema-form-lead

Anthropic commented 7 years ago

@t27 ideally it should follow the behaviour of onChange which passes this object definition:

{
  'modelValue': ctrl.$modelValue,
  'form': form,
  'arrayIndex': scope.$index,
  'arrayIndices': scope.arrayIndices,
  'path': scope.path,
  '$i': scope.$i,
  '$index': scope.$index
}

I would love a PR if you have the time to make it work :)

t27 commented 7 years ago

@Anthropic , Thanks, I think I can implement this for onClick ... The format that you mentioned above, is in the code here right? Also are there any issues/PRs related to this, that you are aware of, that could help while implementing this? (mainly to know what the various parameters mean)

Anthropic commented 7 years ago

@t27 If you search for issue/PRs with comments by @joelwkent relating to arrays there was a fair bit of work done on array code to get the same values available within onChange/destroy relating to that and also it should explain what arrayIndices is all about. I'm on holiday for the next week, but happy to answer any questions the following week.

salimchemes commented 6 years ago

onChange event on tabarray does not fire, is that a known bug? do you know if is there any workaround?

Anthropic commented 6 years ago

@salimchemes are you using an alpha or 0.8.13? I recall a discussion on this at one point, not sure if it got resolved in alphas yet or not.

shiva-git commented 6 years ago

Is this issue resolved ?. Still not bale to access arrayIndex using onClick method inside arrays. Using v 0.8.13

Anthropic commented 6 years ago

@shiva-git this has not been added for onclick yet. @t27 did you end up looking into it?

t27 commented 6 years ago

I did end up looking into it, but I haven't been able to submit a proper PR, we currently use a workaround to get the currently selected tab.

My Workaround Steps

These are a bit sneaky and not necessarily recommended for everyone, they work for the moment

  1. Add a custom classname to your tabarray in the form

    var myCustomClassTag = "customClass"
    {
            "type": "tabarray",
            "key": "myKey",
            "add": "New",
            "remove": "Delete",
            "htmlClass": myCustomClassTag,
    ....
    }
  2. Now, add a button element in your tab array and make a generic onClick handler

                   {
                        "type": "actions",
                        "items": [
                            {
                                "type": "button",
                                "title": "Click me",
                                "style": "btn-primary",
                                "onClick": myCustomClickHandler
                            }
                        ]
                    }
  3. In the click handler, I use the custom HTML class to access the scope of the tab array and return the currently selected tab(scope.selected.tab) and then run your action based on the selected tab number

    function myCustomClickHander() {
        var scope = angular.element('.' + myCustomClassTag).scope();
        return scope.selected.tab;
    }
shiva-git commented 6 years ago

This wouldn't work on array and the requirement is to have button on every element of array instead of generic one

t27 commented 6 years ago

@shiva-git Well, the htmlClass attribute is generic and available to all form types

You only need to write a parent function that is the common click handler for a given array/tabarray field. And, since by definition the fields/buttons in a tabarray are common, you can just attach a common click handler function per button in your form and delegate the appropriate sub tasks/functions within that handler

Do share a sample code that you are working on if i can help

shiva-git commented 6 years ago

I tried this one on normal array (not tabarray) . Looked at almost all the properties in the scope to find out the current selected item of the array (like you suggested scope.selected.tab) but wasn't able to find it. Need help in getting the property name for identifying the specific item of the array.

shiva-git commented 6 years ago

Hey I figured it out. Updated array.html in my decorator to fetch the selected item in array and used the mentioned approach.