Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

fix(tabs): keep stable tab order (when filtering ng-repeat) #153

Closed
wants to merge 6 commits into from

Conversation

darwin
Copy link

@darwin darwin commented Feb 18, 2013

The pane directive should call tabsCtrl.addPane with index, because link function is not guaranteed to be called sequentially. DOM panes may appear or disappear on one-by-one basis in more advanced scenarios with applied ng-repeat filtering.

@ajoslin
Copy link
Contributor

ajoslin commented Feb 18, 2013

Thanks, @darwin! Good fix.

Could you add some evil test cases for when more elements are between panes, to be sure it doesn't goof up? The index values might mess up in this case, but to see if the tabs still work as intended.

Eg:

<tabs>
  <pane>One</pane>
  <div ng-repeat="i in weirdDivs">Hello!</div>
  <pane ng-repeat="p in panes | filter:paneIsAvailable"></pane>
  <div ng-repeat="i in moreWeirdDivs">I'm gonna mess you up!</div>
  <pane>Last pane</pane>
</tabs>

@darwin
Copy link
Author

darwin commented Feb 18, 2013

You are right. Those extra divs mess up the indexing. Now I filter children via .tab-pane class. But it depends on template, I don't know how to distinguish tab panes. Do have a better idea?

@darwin
Copy link
Author

darwin commented Feb 18, 2013

Ok, found a better way. Is it ok now? Let me know if you want me to squash those commits into a single one.

@ajoslin
Copy link
Contributor

ajoslin commented Feb 19, 2013

That works! Though I'm not sure about adding the variable to the scope. It's probably fine though.

I'd say definitely rename the variable to isPane instead of pane, since usually when we use pane as a variable it refers to a pane scope. And maybe prefix it with $ too (__$isPane), so we can be sure no one will want to use it in a controller. This way it looks like a private variable with the underscores and an internal variable with the $, but not an angular core variable. lol 😄

And we can squash it on our end before pushing - you'd have to open a new PR with a new branch and squashed commits otherwise.

@darwin
Copy link
Author

darwin commented Feb 19, 2013

It does not have to be stored in the scope. I could store it on raw DOM element similar way.

It would be great to find a way if directive's X linking phase was applied on a DOM element. Maybe such information is already available in Angular...

@petebacondarwin
Copy link
Member

Actually the more I think about this directive the more I think it should fundamentally change. Instead of using a repeater inside the template we should be using the actual pane element as the tabs and then transcluding their content into the pane content area. This would also help with transclusion of headings.

What do you think?

@ajoslin
Copy link
Contributor

ajoslin commented Feb 19, 2013

That sounds interesting Pete. We could also think about transcluding only the currently selected tab's content (load a tab's content when selected, throw it out when not selected and load the new one). The transclusion way would fix this problem and I'm sure some future problems.

@pkozlowski-opensource
Copy link
Member

Hmmm, I'm really nervous about the fact that it links directives JavaScript code to DOM structure. I'm not sure if I understand correctly the whole problem / solution, but wouldn't it break if we introduce grouping of tabs as discussed in #150?

Ideally directive's JavaScript code should know nothing about CSS and DOM structure. I know it is hard and practically impossible in many cases but this is something we should strive for.

I need to look into this more but I would like to search for an alternative solution.

@pkozlowski-opensource
Copy link
Member

@darwin This is great work and test are good so you are on something. But I would really like to discuss it a bit more and try really hard to keep CSS / DOM knowledge out of JavaScript.

The way I like to think about it is this: let's say that I would like to use a directive with the http://foundation.zurb.com/ or similar. Can I do this by only changing a template?

@darwin
Copy link
Author

darwin commented Feb 20, 2013

I created more general implementation. Now the only assumption is that pane is in the DOM somewhere under tabs, but not necessarily all panes must be on the same DOM level relative to tabs.

The implementation is more complex. I've introduced a way how to sort panes by computing their DOM "order" in relation to tabs element.

@ajoslin
Copy link
Contributor

ajoslin commented Feb 28, 2013

Sorry @darwin! I think the real way to fix this is to make the headers be the actual elements instead of the tab contents. So then the headers will always be in the right order without any of this confurmuddledness 😕 (made up word).

I may be able to work on a refactor soon...

@darwin
Copy link
Author

darwin commented Mar 1, 2013

Ok, no hard feelings. You may close it if you want.

@ajoslin ajoslin closed this Mar 3, 2013
ajoslin added a commit that referenced this pull request Mar 30, 2013
* Tabs transclude to title elements instead of content elements, so the
ordering is always correct (#153)
* Rename `<tabs>` to `<tabset>`, `<pane>` to `<tab>` (#186)
* Add `<tab-heading>` directive, which is a child of a `<tab>`. Allows
HTML in tab headings (#124)
* Add `select` attribute callback when tab is selected (#141)
* Only the active tab's content is actually ever in the DOM
ajoslin added a commit that referenced this pull request Mar 31, 2013
* Tabs transclude to title elements instead of content elements, so the
ordering is always correct (#153)
* Rename `<tabs>` to `<tabset>`, `<pane>` to `<tab>` (#186)
* Add `<tab-heading>` directive, which is a child of a `<tab>`. Allows
HTML in tab headings (#124)
* Add `select` attribute callback when tab is selected (#141)
* Only the active tab's content is actually ever in the DOM
ajoslin added a commit that referenced this pull request Apr 6, 2013
* Tabs transclude to title elements instead of content elements, so the
ordering is always correct (Closes #153)
* Rename `<tabs>` to `<tabset>`, `<pane>` to `<tab>` (Closes #186)
* Add `<tab-heading>` directive, which is a child of a `<tab>`. Allows
HTML in tab headings (Closes #124)
* Add `select` attribute callback when tab is selected (Closes #141)
* Only the active tab's content is now actually ever in the DOM
ajoslin added a commit that referenced this pull request Apr 8, 2013
* Rename 'tabs' directive to 'tabset', and 'pane' directive to 'tab'.
 The new syntax is more intuitive; The word pane does not obviously
 represent a subset of a tab group. (Closes #186)
* Add 'tab-heading' directive, which is a child of a 'tab'. Allows
HTML in tab headings. (Closes #124)
* Add option for a 'select' attribute callback when a tab is selected.
 (Closes #141)
* Tabs transclude to title elements instead of content elements. Now the
 ordering of tab titles is always correct. (Closes #153)
* Only the active tab's content is ever present in the DOM. This is
 another plus of transcluding tabs to title elmements, and provies a
 performance increase.

BREAKING CHANGE: The 'tabs' directive has been renamed to 'tabset', and
 the 'pane' directive has been renamed to 'tab'.

    To migrate your code, follow the example below.

    Before:

    <tabs>
      <pane heading="one">
        First Content
      </pane>
      <pane ng-repeat="apple in basket" heading="{{apple.heading}}">
        {{apple.content}}
      </pane>
    </tabs>

    After:

    <tabset>
      <tab heading="one">
        First Content
      </tab>
      <tab ng-repeat="apple in basket" heading="{{apple.heading}}">
        {{apple.content}}
      </tab>
    </tabset>
ajoslin added a commit that referenced this pull request Apr 9, 2013
* Rename 'tabs' directive to 'tabset', and 'pane' directive to 'tab'.
 The new syntax is more intuitive; The word pane does not obviously
 represent a subset of a tab group. (Closes #186)
* Add 'tab-heading' directive, which is a child of a 'tab'. Allows
HTML in tab headings. (Closes #124)
* Add option for a 'select' attribute callback when a tab is selected.
 (Closes #141)
* Tabs transclude to title elements instead of content elements. Now the
 ordering of tab titles is always correct. (Closes #153)
* Only the active tab's content is ever present in the DOM. Provides an
 increase in performance.

BREAKING CHANGE: The 'tabs' directive has been renamed to 'tabset', and
 the 'pane' directive has been renamed to 'tab'.

    To migrate your code, follow the example below.

    Before:

    <tabs>
      <pane heading="one">
        First Content
      </pane>
      <pane ng-repeat="apple in basket" heading="{{apple.heading}}">
        {{apple.content}}
      </pane>
    </tabs>

    After:

    <tabset>
      <tab heading="one">
        First Content
      </tab>
      <tab ng-repeat="apple in basket" heading="{{apple.heading}}">
        {{apple.content}}
      </tab>
    </tabset>
ajoslin added a commit that referenced this pull request Apr 28, 2013
* Rename 'tabs' directive to 'tabset', and 'pane' directive to 'tab'.
 The new syntax is more intuitive; The word pane does not obviously
 represent a subset of a tab group. (Closes #186)
* Add 'tab-heading' directive, which is a child of a 'tab'. Allows
HTML in tab headings. (Closes #124)
* Add option for a 'select' attribute callback when a tab is selected.
 (Closes #141)
* Tabs transclude to title elements instead of content elements. Now the
 ordering of tab titles is always correct. (Closes #153)

BREAKING CHANGE: The 'tabs' directive has been renamed to 'tabset', and
 the 'pane' directive has been renamed to 'tab'.

    To migrate your code, follow the example below.

    Before:

    <tabs>
      <pane heading="one">
        First Content
      </pane>
      <pane ng-repeat="apple in basket" heading="{{apple.heading}}">
        {{apple.content}}
      </pane>
    </tabs>

    After:

    <tabset>
      <tab heading="one">
        First Content
      </tab>
      <tab ng-repeat="apple in basket" heading="{{apple.heading}}">
        {{apple.content}}
      </tab>
    </tabset>
ajoslin added a commit that referenced this pull request May 9, 2013
* Rename 'tabs' directive to 'tabset', and 'pane' directive to 'tab'.
 The new syntax is more intuitive; The word pane does not obviously
 represent a subset of a tab group. (Closes #186)
* Add 'tab-heading' directive, which is a child of a 'tab'. Allows
HTML in tab headings. (Closes #124)
* Add option for a 'select' attribute callback when a tab is selected.
 (Closes #141)
* Tabs transclude to title elements instead of content elements. Now the
 ordering of tab titles is always correct. (Closes #153)

BREAKING CHANGE: The 'tabs' directive has been renamed to 'tabset', and
 the 'pane' directive has been renamed to 'tab'.

    To migrate your code, follow the example below.

    Before:

    <tabs>
      <pane heading="one">
        First Content
      </pane>
      <pane ng-repeat="apple in basket" heading="{{apple.heading}}">
        {{apple.content}}
      </pane>
    </tabs>

    After:

    <tabset>
      <tab heading="one">
        First Content
      </tab>
      <tab ng-repeat="apple in basket" heading="{{apple.heading}}">
        {{apple.content}}
      </tab>
    </tabset>
ajoslin added a commit that referenced this pull request May 9, 2013
* Rename 'tabs' directive to 'tabset', and 'pane' directive to 'tab'.
 The new syntax is more intuitive; The word pane does not obviously
 represent a subset of a tab group. (Closes #186)
* Add 'tab-heading' directive, which is a child of a 'tab'. Allows
HTML in tab headings. (Closes #124)
* Add option for a 'select' attribute callback when a tab is selected.
 (Closes #141)
* Tabs transclude to title elements instead of content elements. Now the
 ordering of tab titles is always correct. (Closes #153)

BREAKING CHANGE: The 'tabs' directive has been renamed to 'tabset', and
 the 'pane' directive has been renamed to 'tab'.

    To migrate your code, follow the example below.

    Before:

    <tabs>
      <pane heading="one">
        First Content
      </pane>
      <pane ng-repeat="apple in basket" heading="{{apple.heading}}">
        {{apple.content}}
      </pane>
    </tabs>

    After:

    <tabset>
      <tab heading="one">
        First Content
      </tab>
      <tab ng-repeat="apple in basket" heading="{{apple.heading}}">
        {{apple.content}}
      </tab>
    </tabset>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants