2

I'm creating a reusable item picker component using Angular 1.5. The picker has a search field and a list of items to choose from. An example use case for the picker is a popup where the user selects some items and then has a "Continue" button to proceed.

Conceptually, the search field and the list of items belong to the component and the "Continue" button belongs to the surrounding dialog. However, I want to position the button next to the search field. In some cases there are no extra buttons, sometimes one extra button, sometimes two.

Something like this:

Item picker

What is the best way to create such a component?

Options I've thought of:

  1. Create a component / directive for the item picker, put the button before or after the directive in the HTML, and use CSS to position the button.

    Here the positioning of the button is ugly and fragile, as it's not in the proper position within the HTML. It would probably need a wrapper div and absolute positioning on top of the picker component:

    <div style="position: relative"> <item-picker></item-picker> <button name="Continue" ng-click="submit()" style="position:absolute; top:5px; right: 5px"></button> </div>

  2. Somehow pass the buttons and callbacks as parameters to the item picker component. Here the ugliness is in the hard-coding of the buttons and styles and amount of buttons:

    <item-picker btn1-text="Continue" btn1-style="primary" btn1-callback="submit()" btn2-text="Cancel" btn2-style="secondary" btn2-callback="cancel()"></item-picker>

    I'm unsure whether the button configuration and callbacks could be passed as a single configuration object. I'm mainly concerned about the callback functions, whether they will work properly if passed through a configuration object instead of proper '&' callback binding.

  3. Stop trying to make the picker into a component / directive and just use <ng-include> to include the picker code which reads the button configuration from the scope. Ugliness is in lack of scoping and not using components.

Is there some best practise for such cases?

2
  • 1
    There may be a 4th option which is to use ng-transclude Commented Sep 23, 2016 at 6:31
  • @o4ohel looks like just what I wanted. Care to write an answer? (I can write one too) Commented Sep 23, 2016 at 6:53

1 Answer 1

1

One possible solution is to use ng-transclude, so your code could look something like:

Markup

<item-picker>
  <button ng-click="parentScopeFn()">Btn 1</button>
  ...
</item-picker>

Directive

angular.module('myApp', [])
.directive('itemPicker', function() {
  return {
    restrict: 'E',
    transclude: true,
    scope: {
      ...
    },
    templateUrl: 'item-picker.html'
  };
});

itemPicker template markup

<div class="item-picker">
  <div class="item-picker-controls">
    <div class="item-picker-search"><input type="search" ng-model="..."></div>
    <div class="btn-group" ng-transclude></div>
  </div>
  <ul class="item-picker-list">
    <li ng-repeat="item in items" ng-bind="item"></li>
  </ul>
</div><!-- end item-picker template -->

Of course the above code is just an example and is making a lot of assumptions about your itemPicker component. Also, you'll still need to use CSS to position your buttons, but it might be easier to reason with b/c it'll be in the context of your component.

Note You could also make use of "multi slot transclusion". This is probably useful in cases where the number and type of buttons you'll have is predictable and you want them arranged in a consistent way no matter how they are placed in the markup.

Hope this helps.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.