-2

I'm currently trying to style the first word of a string inside my Angular ngFor loop. Somehow the class get's applied but not the style inside my CSS file. Also inline styling don't works - why?

This is my CSS I want to apply:

#page-image-title-table .first-entry-word {
  font-weight: 500;
}

This is my function to wrap my first word into an element with my class above:

formatTableEntry(tableEntry: string): string {
  const tableEntryParts = tableEntry.split(' ');
  const firstWord       = tableEntryParts[0];

  tableEntryParts.shift();

  const restOfString = tableEntryParts.join(' ');

  return `<span class="first-entry-word">${firstWord}</span> ${restOfString}`;
}

And this is my HTML with my loop:

<div id="page-image-title-table">
  <div class="page-image-title-table-row" *ngFor="let tableEntry of tableEntries">
    <span [innerHTML]="formatTableEntry(tableEntry)"></span>
  </div>
</div>

You can see my working example here:

https://angular-ivy-g7ov5s.stackblitz.io

Mr. Jo
  • 4,946
  • 6
  • 41
  • 100
  • Please don't downvote without any description whats missing. I've added some code and a working example. Whats needed next? – Mr. Jo Jan 11 '21 at 14:22
  • 2
    Your working example doesn’t work for me. In Chrome it shows just the spinning blue circle in the top right corner, and in Firefox it only keeps saying “starting dev server” for over a minute, without ever getting anywhere. – CBroe Jan 11 '21 at 14:29
  • 1
    Not downvoting, but this has been answered many times, so much that one of the most popular answers is even a duplicate: https://stackoverflow.com/questions/44210786/style-not-working-for-innerhtml-in-angular – Z. Bagley Jan 11 '21 at 14:29

1 Answers1

3

I see multiple issues here.

  1. Binding a function to directive [innerHTML]="formatTableEntry(tableEntry)" will lead to performance issues in default change detection strategy.

  2. Using innerHTML binding like you're attempting is not elegant in Angular.

  3. font-weight: 500 is the default weight value. Bold is equal to 700.

  4. Perhaps unimportant to the actual issue, but the Stackblitz doesn't seem to work for me in FF and Chrome.

Solution

You could whip up a quick pipe to split the sentences to the required format.

split.pipe.ts

@Pipe({
  name: 'split', 
  pure: true
})
export class SplitPipe implements PipeTransform {
  transform(value: any, args?: any): any {
    if (!value) {
      return null;
    }

    return value.reduce((acc, curr) => {
      const [first, ...rest] = curr.split(" ");
      acc.push({ first: first, rest: rest.join(" ") });
      return acc;
    }, []);
  }
}

It could then be use in conjunction with *ngFor directive akin to keyvalue pipe.

Try the following

app.component.ts

@Component({
  selector: "my-app",
  template: `
    <div id="page-image-title-table">
      <div 
        class="page-image-title-table-row" 
        *ngFor="let tableEntry of (tableEntries | split)"
      >
        <span>
          <span class="first-entry-word">{{ tableEntry.first }}</span>
          {{ tableEntry.rest }}
        </span>
      </div>
    </div>
  `,
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  tableEntries = [
    "First element of the array",
    "Second sample element of the array",
    "lorem ipsum dolor sit amet",
    "Quick brown fox jumps over the lazy dog"
  ];
}

app.component.css

#page-image-title-table .first-entry-word {
  font-weight: 700;
}

Working example: Stackblitz

ruth
  • 29,535
  • 4
  • 30
  • 57
  • Works nicely (My font has 400 as normal and 500 for a bit of bold). Thanks a lot for showing me the way to deal with this. It works how it should. Thanks mate! – Mr. Jo Jan 11 '21 at 14:57