The Angular2 team has done a good job with their newish Bootstrap Angular2 components. I’ve been playing with them for a while.
I started out with the Tabs component. My tendency is to gravitate toward the things that are useful to me in the moment. Since there are many Angular 1.x apps that I write/support, I happened to be working on an Anuglar 1.x tabbed view and had recently blogged about tabbed views using ui-router.
At any rate, the main thing I wanted to do is to be able to manipulate the selected tab, examine how change tracking worked, and discover how flexible the Angular2 bootstrap components were. In terms of change tracking, dynamically adding tabs and then choosing the most recently added tab as the active tab seemed to be relevant to my desired use case.
The demo I came up does this very thing. There is a single button in the view that allows for adding a tab. Since I’m not an expect with Typescript, the demo afforded me the opportunity to play around with basic Typescript usage such as integrating with external libraries.
Some of the relevant bits of the code include pushing the changes/list of tabs up to the parent container. I thought this would be useful to examine change tracking and interacting with components in a sort-of parent/child relationship.
EventEmitters appear to be the preferred method for communicating between components. This can be seen in my “tab” component.
@Output() tabAdded = new EventEmitter(); @Output() tabSetCreated = new EventEmitter();
Within the app.component, we specify the event handlers:
<tabs [tabList]="this.tabList" [sharedData]="this.sharedData" (tabAdded)="tabAdded($event)" (tabSetCreated)="tabSetCreated($event)"></tabs>
The events are fired when the add button is clicked and when the child component is initialized. Having a handle to the tabSet within the parent is all that’s needed, really, to set the active tab. The tabSet is the “sharedData.” I use a secondary array that contains the list of tabs. I split it into two separate shared objects to test and to confirm that modifying something in the parent/child did cause a UI update.
@Input() set tabList(tabList: Array<Object>) { this._tabs = tabList; } @Input() set sharedData(sharedData: any) { this._sharedData = sharedData; }
This is a handy mechanism for passing around shared objects between components. I also have kind of grown to like how objects’ types have to be specified within Typescript. It’s not overly rigid since a plain JavaScript object (“any”) can be specified.
All in all, I liked how the Angular2 bootstrap tab component behaved. The only weirdness I noticed was using the select() method to set the active tab. It didn’t seem to work with the dynamic tabs. I think it was due to a timing issue. I tried various Observable mechanisms and timeouts to fix the issue, but none worked. I fell back to simply setting the “activeid” which seemed to work consistently.
Other points of interested – there is an external JavaScript “lorem ipsum” generator that I used for generating the content of the tabs. It is the external JavaScript library that I integrated into my TypeScript code. Figuring this out was interesting in and of itself, while not being terribly difficult to accomplish.
This is something I find really useful adding tabs during run time. The one thing I am confused about is in your app what type of data I can provide in your tabList array?
It would be nice to provide it a component, but you then would probably need to use entryComponent and ViewContainerRef. If its possible could you give example of what the tab data might look like?
Very good points – I’ll look into providing an updated demo that, at the very least, can tie into the router for components within the tabs.
Thanks for looking into it, I guess I had forgot that I could do routing with this too. Although being able to do this without routing would be preferable