简体   繁体   中英

Why did Angular deprecate the old “replace” directive option?

In the old Angular 1.x we could build directives and have an options to set "replace": true in the configuration which would allow you to tell Angular to replace the entire DOM element with whatever your directive was comprised of.

I am fairly new to Angular 2+, but so far we only seem to have 2 options for building a component in the same manner:

1) Use the element selector like this <app-my-component></app-my-component>

2) Use the attribute selector like this <div app-my-component></div>

The issue is I see problems with both of these:

Using method #1 can disrupt CSS stylings as Angular will place an extra DOM element into the page which means if you have an HTML structure like comprised of a <ul> and children <li> elements and you want to make the <li> elements a reusable component then your resulting DOM looks like this:

<ul>
    <app-my-component>
        <li>Inner</li>
    </app-my-component>
</ul>

Which would effectively break any CSS targeting ul > li .

Using method #2 allows us to fix the CSS styling issue, but removes the abstraction that a component is supposed to provide as now a consumer of the component has to have knowledge about the element type needed:

<ul>
    <li app-my-component>
        Inner
    </li>
</ul>

In the above case the developer has to know to use a <li> in order for things to work properly. This is a very simple example, but more complex scenarios could be less intuitive to the developer causing headaches.

Take a look at this example. Due to the nature of the underlying HTML/CSS I had to setup these 2 (primary/secondary) components like this and use an internal <ng-content> to display the navigation correctly. As you can see having to stick <li> elements inside of the parent <div> looks and feels weird and adds the need for the developer to know about the underlying HTML.

<div app-platform-navigation-primary label="Test" icon="account_box" link="#">
    <li app-platform-navigation-secondary label="Test2" link="#"></li>
    <li app-platform-navigation-secondary label="Test3" link="#"></li>
    <li app-platform-navigation-secondary label="Test4" link="#"></li>
    <li app-platform-navigation-secondary label="Test5" link="#"></li>
</div>

Summary

Overall, both methods have their pros and cons, but I feel like I could get the best of both worlds if we could still use the "replace" method which allows you to develop using method #1 which provides all of the abstraction you need, but would not add an "extra" DOM element onto the page which would allow CSS to continue to work.

What were the downfalls of doing this that caused the Angular team to remove these capabilities? And is there any solution to do it how I would like to do it?

When developers want to use your component, they have to look at your documentation to see what the name of the selector is. So what is the difference between you instructing the developers to use <app-my-component> vs <li app-my-component> ? Note that component selectors support CSS selectors. In other words, you can ensure that your component only works with a <li> host element:

@Component({
  selector: 'li[app-my-component]'
  ...
})

With a strict selector as shown, where you specify both the element and the attribute, you can prevent developers from using your component outside of its intended use.

For your example use case:

@Component({
  selector: 'ul[app-platform-navigation-primary]'
  ...
})

and..

@Component({
  selector: 'li[app-platform-navigation-secondary]'
  ...
})

The host element of a component does not have to be a <div> . It can be a <ul> , <li> or whatever else.

If you wish to abstract the fact that your component is using <ul> and <li> internally, then take a look at this SO answer . This answer demonstrates how you can wrap each child component inside <li> s within your parent component.

In summary, it is possible to achieve the same result as in AngularJs where you do not have extra elements but without the use of replace .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM