Unable to add css classes to dynamically created grid children


#1

I have a component with a dynamically created grid with one row to mimic a kind of custom tabview behaviour, like this.

import {Component,ElementRef,EventEmitter,Input,OnInit,Output,ViewChild} from '@angular/core';
import {GridLayout,ItemSpec} from "ui/layouts/grid-layout";
import buttonModule = require("ui/button");

@Component({
  selector: 'TabsBar',
  template: `<GridLayout #tabGrid rows="60"></GridLayout>`,
  styles: [`
    .tab { padding:5; }
    .tab-active { border-color: black; border-width: 0 0 4 0; }
  `]
})
export class TabsBarComponent implements OnInit {
  @Input() items:Array<any> = undefined;
  @Output() selectedIndexChanged = new EventEmitter();
  @ViewChild('tabGrid') tabGrid: ElementRef;

  constructor() {}

  public ngOnInit() {
    this.createGrid();
  }

  private createGrid() {
    this.items.forEach((item,index) => {
      this.tabGrid.nativeElement.addColumn(new ItemSpec(1, "star"));
      let tab = new buttonModule.Button();
      tab.text = item.title;
      tab.className = 'tab'; // doesn't seem to do anything
      // tab.cssClasses = 'tab'; // causes error: node.cssClasses.forEach is undefined
      tab.on('tap',(event) => {
        // tab.cssClasses = 'tab tab-active'; // currently not working
        // emit event to parent
        this.selectedIndexChanged.emit({
          object: item,
          selectedIndex: index
         });
      });
      this.tabGrid.nativeElement.addChild(tab); // add new tab to grid
      GridLayout.setColumn(tab,index); // set new tabs grid position
    });
  }
}

The problem is that neither the tab.className nor the tab.cssClasses seem to work. The former just doesn’t seem to affect anything, the latters results in an error:

CONSOLE ERROR file:///app/tns_modules/@angular/core/bundles/core.umd.js:3004:32: EXCEPTION: Uncaught (in promise): Error: Error in ./ContactsPage class ContactsPage - inline template:35:57 caused by: node.cssClasses.forEach is not a function. (In 'node.cssClasses.forEach(function (c) { return selectorClasses.push(_this.class[c]); })', 'node.cssClasses.forEach' is undefined)

Any advice would be much appreciated.
Thanks!


#2

Couple things to try…

First, the cssClasses property actually has methods to add/remove class names (it implements the Set<T> interface, FWIW). So what you want to do is this:

tab.cssClasses.add('tab');

This should eliminate the error you were hitting this approach.

Second, where are you defining the tab CSS class? There is a bug that should be fixed in 2.5 (I think) where CSS defined “too deep” in the custom component structure won’t load. You can review the details here: https://github.com/NativeScript/NativeScript/issues/1639

For debugging, try defining your CSS class in app.css or some “known working” stylesheet in your app. If that fixes your styles, the problem is that your CSS with the tab class is not loading properly. There are workarounds, or you can A) wait for 2.5, or B) define your styles in a CSS sheet closer to the root view.

Hope that helps.


#3

Thanks for your explanation @toddanglin! In the meantime to avoid css class issues you describe, I’ve just solved it by using setInlineStyle:

    let commonTabCss = `
      font-size: 16;
      background-color: ${this.backgroundColor};
      color: ${this.color}; 
      border-color: ${this.activeColor};
    `
    let normalTabCss = `${commonTabCss} border-width: 0 0 0 0;`;
    let activeTabCss = `${commonTabCss} border-width: 0 0 2 0;`;

    tab.setInlineStyle(normalTabCss);

Another advantage is that this allows me to provide colors as inputs on the component.

Thanks again!