1
votes

I currently have this problem: I made 3 directives (check plunkr for a 'reduced' test case, dont mind the closures they come from Typescript) that control tabs, using a controller to keep them grouped, since I can have more than one tabbed content on the current view. The problem happens when the tab itself has some bindings that are located outside of the scope, and when the tab is 'transcluded' in place, the binding never updates because the scope is different.

Here is the plunkr http://plnkr.co/edit/fnw1oV?p=preview and here is the "tab transclude" part that is important

    this.link = function (scope, element, attr) {
        var clickEvent, el, item;
        item = scope.item;
        console.log(scope);

        el = item.element.filter('.is-tab');

        el.addClass('picker-tabs-item');

        clickEvent = 'tabs.select(item);';
        if (el.is('[ng-click]')) {
            clickEvent += el.attr('ng-click') + ';';
        }

        el.attr('ng-click', clickEvent);
        el.attr('ng-class', 'tabs.classes(item)');

        item.element = $compile(item.element)(scope);

        element.replaceWith(item.element);
    };

The current approach feels hacky (keeping the original scope and element in an array). Plus in my app, the data is loaded after the tabs were loaded, so it can't even retain some initial state. The tabs look like this right now:

current tabs

and the way it should look like (but doesn't work, as you can see clicking one tab select all of them):

the way it should be

A real tab code from my app:

<div class="clearfix" login-space user-space>
<div class="picker clearfix" ng-class="{'to-hide': user.data.get('incomplete') || checkout.checkoutForm.$invalid}">
    <div class="pick-title icon icon-pay">Forma de Pagamento</div>
    <div class="for-hiding">
        <div tabs="pagamento">
            <div tab="/templates/tabs/plans/credito" selected="true">
                <button class="is-tab clicky" ng-disabled="checkout.disabledTab('credito')" type="button">
                    Cartão
                    <span class="pick-pill-indicator-placeholder" ng-bind="checkout.total('credito')"></span>
                </button>
            </div>
            <div tab="/templates/tabs/plans/debito">
                <button class="is-tab clicky" ng-disabled="checkout.disabledTab('debito')" type="button">
                    Débito
                    <span class="pick-pill-indicator-placeholder" ng-bind="checkout.total('debito')"></span>
                </button>
            </div>
            <div tab="/templates/tabs/plans/boleto">
                <button class="is-tab clicky" ng-disabled="checkout.disabledTab('boleto')" type="button">
                    Boleto
                    <span class="pick-pill-indicator-placeholder" ng-bind="checkout.total('boleto')"></span>
                </button>
            </div>
        </div>
    </div>
</div>
</div>

login-space and user-space are directives just to assign it to the login and user controllers. checkout is the current controller inside ui-view.

$stateProvider.state('planos.checkout', {
    url: '/checkout',
    templateUrl: '/templates/partials/plans/checkout',
    controllerAs: 'checkout',
    controller: Controllers.Checkout,
    data: {
        allowed: false,
        enclosed: true
    }
});

since the checkout controller must be instantiated only once, I can't reinstantiate it, but still need to access it's functions and bound data.

'/templates/partials/plans/checkout' contains the tab code above (so yes, technically it's in the same scope as checkout controller)

2

2 Answers

0
votes

In your plunker, changing your tabs to this:

<span data-subctrl="">{{ subctrl.sum('credito') }}</span>

Showed the sum. I looked at what subctrl was and you have it as a directive, that's why subctrl.sum is not working. Plunker with it working: http://plnkr.co/edit/qwEHMqfzJ6pC79hM8cDj?p=preview

If that's not what's wrong with your application, then please describe it a little more.

0
votes

Solved this by removing the html content of the tab, and applying a different scope to the inner content, then reattaching to the original element.

this.link = function (scope, element, attr) {
    var clickEvent, el, item;
    item = scope.item;
    console.log(scope);

    el = item.element.filter('.is-tab');
    var contents = el.html(); //added
    el.empty(); // added

    el.addClass('picker-tabs-item');

    clickEvent = 'tabs.select(item);';
    if (el.is('[ng-click]')) {
        clickEvent += el.attr('ng-click') + ';';
    }

    el.attr('ng-click', clickEvent);
    el.attr('ng-class', 'tabs.classes(item)');

    item.element = $compile(item.element)(scope);
    item.element.append($compile('<div>' + contents + '</div>')(item.scope)); //added

    element.replaceWith(item.element);
};