3

I want to share some HTML (layout) between some of my components but not all.

app.compomonent.html:

<div class="classA">
  <router-outlet></router-outlet>
</div>

Some of my components, but not all, share some HTML:

Component X

<div class="classB">
  <h2>{{Subtitle}}</h2>
</div>
<div class="classC">
  X_SPECIFIC_HTML
</div>

Component Y

<div class="classB">
  <h2>{{Subtitle}}</h2>
</div>
<div class="classC">
  Y_SPECIFIC_HTML
</div>

I want to define the shared HTML (note the data binding) with a placeholder for the actual component HTML:

<div class="classB">
  <h2>{{Subtitle}}</h2>
</div>
<div class="classC">
  INSERT_COMPONENT_HTML_HERE
</div>

So my components can be defined like this:

Component X

X_SPECIFIC_HTML

Component Y

Y_SPECIFIC_HTML

Current routes:

const appRoutes: Routes = [
  { path: 'x', component: XComponent },
  { path: 'y', component: YComponent }
];

Is this possible?

4
  • Have you tried using a service to just change the data in your component instead of creating another component? Commented Jul 20, 2017 at 6:38
  • Please note the example is extremely simplified. Changing data is unfortunately not a viable solution. The requirement is to handle shared layout. Commented Jul 20, 2017 at 8:54
  • I see. It is possible by using another router-outlet inside your shared component/template, can you share how you define your routing? Commented Jul 20, 2017 at 9:17
  • Sure, have just edited my question. There is nothing fancy about the routes. I can create a more complete example if needed but it will take some time. Commented Jul 20, 2017 at 10:36

1 Answer 1

5

Got help else where...

Sharing HTML is quite easy using "content projection".

The data binding is a bit more tricky and I managed to do so using a BehaviorSubject.

page-layout.component (the shared HTML)

<div style="background-color: red;">
  <h2>subtitle: {{subtitle}}</h2>
  <ng-content></ng-content>
</div>
import { Component, OnInit } from '@angular/core';
import { LayoutService } from '../../services/layout.service';

@Component({
  selector: 'page-layout',
  templateUrl: './page-layout.component.html',
  styleUrls: ['./page-layout.component.css']
})
export class PageLayoutComponent implements OnInit {

  subtitle = '';

  constructor(private LayoutService: LayoutService) {
  }

  ngOnInit() {
    this.LayoutService.observable.subscribe(x => {
      if (console) {
        console.log('PageLayoutComponent, subscribe: ' + JSON.stringify(x));
      }
      this.subtitle = x.subtitle;
    });
  }
}

assembly-list.component (a component using the shared HTML)

<page-layout>
  <p>ToDo</p>
</page-layout>
import { Component, OnInit } from '@angular/core';
import { LayoutService } from '../../services/layout.service';

@Component({
  selector: 'assembly-list',
  templateUrl: './assembly-list.component.html',
  styleUrls: ['./assembly-list.component.css']
})
export class AssemblyListComponent implements OnInit {

  constructor(private LayoutService: LayoutService) {
  }

  ngOnInit() {
    this.LayoutService.emitTitle(
      'AssemblyListComponent1', 'AssemblyListComponent2'
    );
  }
}

layout-service (the data binding for the shared HTML)

import { Component, Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

export interface ILayoutServiceData {
  title: string;
  subtitle: string;
}

@Injectable()
export class LayoutService {

  private behaviorSubject: BehaviorSubject<ILayoutServiceData> = 
    new BehaviorSubject({title: null, subtitle: null});

  observable = this.behaviorSubject.asObservable();

  emitTitle(title: string, subtitle: string) {
    if (console) {
      console.log(`LayoutService.emitTitle(\'${title}\', \'${subtitle}\'`);
    }
    const data: ILayoutServiceData = {
      title: title,
      subtitle: subtitle
    };
    this.behaviorSubject.next(data);
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Have you tried making this work with a ngModel in the shared component?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.