Join the Stack Overflow Community
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

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?

share|improve this question
1  
There may be a 4th option which is to use ng-transclude – o4ohel 11 hours ago
    
@o4ohel looks like just what I wanted. Care to write an answer? (I can write one too) – Sampo 11 hours ago

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.

share

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.