Several pages with the same structure in Angular

I am relatively new to Angular and I am struggling to create the same behavior for multiple pages using a common module.

Here's the situation: I'm creating a CRUD SPA with multiple "pages" (using routing). It turns out that some of these pages have the same structure and behavior and differ only visually in how the items appear in the list and its details when selected. Think of multiple Asana pages where the only difference between the pages is the way the list and details are displayed.

I was thinking about creating a module for each of these pages, but it seemed to me that he just copied and pasted all the code to just change a small part of the files (updating would be a nightmare too).

The solution I am trying to achieve is to create a single component / html / css master CRUD module where I can somehow parameterize which renderer to use for each page. Or any other solution that has as few copies-paste as possible.

Thanks for the help.

+3


source to share


2 answers


I read about the tool and some other things like dynamically created components, but none of them were what I wanted (especially considering the learning curves). So it took me a while, but I found a (pretty crazy) solution myself.

I first created a basic module. Inside it, I created PageComponent

that calls the two parts of the pages that I need, one for the list and the other for the details (like Asana). The template page.component.html

looks like this:

<div class="mdl-grid">
    <div class="mdl-cell mdl-cell--8-col">
        <app-list></app-list>
    </div>
    <div class="mdl-cell mdl-cell--4-col">
        <app-details></app-details>
    </div>
</div>`

      

In this basic module I created an abstract base class for each of the components that are necessary to me ( AbstractListComponent

and AbstractDetailsComponent

). I had some problems with dependency injection and auto-generation of variables using the access word in the constructor, so my solution was as follows:

export abstract class AbstractDetailsComponent {
    protected service: BaseService;

    protected constructor(service: BaseService) {
        this.service = service;
    }
}

      

Note that I did not use a decorator @Component

, as it will be ignored (in the PageComponent

same). Another thing is that some classes and interfaces Base*

have been created for consistency (for example BaseService

).

As you can see, no one will respond when PageComponent

asking for <app-list>

and <app-details>

. This is where the crazy part begins.

For each page, I created a module and within it components filling in the blanks. In addition, the main component for the page extends PageComponent

. For example, in my application, I have a Skills page that leads to the following SkillsComponent

:

@Component({
    selector: 'skills-page', // doesn't really matter, this will be called by the router
    templateUrl: '../base-module/page.component.html',
    styleUrls: [ '../base-module/page.component.css', './skills.component.css' ]
})
export class SkillsComponent extends PageComponent { }

      



Note that templateUrl

one of the styles also points to files inside the base module. This was the way I found to use the same page structure between all pages.

Now the spaces. The two components I need are similar. Basically, I extend the base class for each one and inject the correct service. Here is SkillDetailsComponent

:

@Component({
    selector: 'app-details', // <-- the name required by the PageComponent template
    templateUrl: './skill-details.component.html',
    styleUrls: [ '../base-module/details.component.css', './skills-details.component.css' ]
})
export class SkillsDetailsComponent extends DetailsComponent {
    public constructor(service: SkillsService) {
        super(service);
    }
}

      

selector

- this is exactly what is required page.component.html

. All listing and detail components for all pages use the same approach. This makes the same template useful for all pages, since the selector is the same.

The constructor is another matter. I had to do it this way in order to introduce the correct service.

The final file structure looks like this:

app/
    ├ base-module/
    │    ├ base.component.css
    │    ├ base.component.html
    │    ├ base.component.ts
    │    ├ base.module.ts
    │    ├ details.component.css
    │    ├ details.component.ts
    │    ├ list.component.css
    │    ├ list.component.html
    │    └ list.component.ts
    └ skills-module/
        ├ skills-details.component.css
        ├ skills-details.component.ts
        ├ skills-list.component.css
        ├ skills-list.component.ts
        ├ skills.component.css
        ├ skills.component.html
        ├ skills.component.ts
        └ skills.module.ts

      

I don't know if this is the best solution, but it's kind of necessary. I found it difficult to explain all the steps I took (usually a sign of a too complex solution), but I hope this is clear.

+1


source


I assume you are using ng-route

. Try to check ui-router

https://github.com/angular-ui/ui-router



UI-Router is a standard client side routing framework based on the AngularJS standard that supports nested views. The concept of UI-Router is to model views as a hierarchical tree of states.

0


source







All Articles