Why is `replace` property deprecated in AngularJS directives? [duplicate]
Asked Answered
S

4

112

According to the API docs, directives' replace attribute is deprecated, so in the future, all directives will behave with the current default of replace: false.

This removes developers' ability to replace an element directive's element, with no apparent replacement for this functionality.

See this plunk for an example of how element directives work with and without replace: true.

Why is this useful attribute being deprecated with no replacement?

Sclerosis answered 12/6, 2014 at 22:37 Comment(3)
probably for performance and/or simplicity: it preserves properties of the element if you don't replace it. i noticed that angular does define props (not attribs, which are duped ok) like 'ng-1402613834652'. if other parts of angular can grab a ref to the element and not have to worry about it going stale, there's a lot less cross-checking to perform when running data/view updates.Laguna
Just thought I'd add that replacing via $('selector').replaceWith(content) in the link function is a very simple solution, although not nearly as nice as "replace: true". It also assumes jquery, not sure if angular's jqLite supports replaceWith.Sirmons
I actually had to use this recently when I wanted to dynamically add ng-click to an existing element via a directive. #22116970Schnitzler
A
71

UPDATE

One of the collaborators has said it won't be removed, but known bugs will not be fixed. https://github.com/angular/angular.js/commit/eec6394a342fb92fba5270eee11c83f1d895e9fb#commitcomment-8124407

ORIGINAL

Here is the commit of this change: https://github.com/angular/angular.js/commit/eec6394a342fb92fba5270eee11c83f1d895e9fb

The replace flag for defining directives that replace the element that they are on will be removed in the next major angular version. This feature has difficult semantics (e.g. how attributes are merged) and leads to more problems compared to what it solves. Also, with WebComponents it is normal to have custom elements in the DOM.

It sounds to me like its a combination of complexity vs benefit to maintain support.

And apparently one reason dev were using it because they prefered semantically correct markup to be injected , thus replacing the custom directive tag.


Read the comments lower down on that link and apparently many people want it to stay.

Alga answered 12/6, 2014 at 23:5 Comment(7)
Last comments have good news for us, replace wont be removed :)Apotheosize
I'm on angularJS 1.3.0 and it looks like it is removedErlineerlinna
Edgar: it's not removed in 1.3.0.Gumma
I have run into problems with replace myself and even prepared a PR to fix them: github.com/angular/angular.js/pull/10733. The discussion thread for this PR contains some interesting points on why replace is broken and how to work around some of the problems it causes.Scottscotti
This is disappointing. I've found that replace is essential when your directive template are transcluding, and contain hierarchically dependent elements like ul|ol/li. I use replace to ensure that the markup for directives that construct things like menus and whatnot with ul/li end up with markup that actually works. I truly hope WebComponents (which I have not researched much) have an alternative way of solving such a problemGesture
I found this line in github link to be useful in tracing why did the angular team come up with this thought. It says: Also, with WebComponents it is normal to have custom elements in the DOM.Toandfro
I was just reading an article for optimizing angularjs apps and it suggested using replace:true on custom directives to lower the number of DOM elements and increase performance. Wondering how valid is that?Divebomb
P
20

If you fear that replace: true will be removed in next version, you can use a postCompile function to replicate the behavior.

/// Replace element with it's first child
Utils.replaceWithChild = function(element) {
    var child = angular.element(element[0].firstChild);
    Utils.mergeAttributes(element, child);
    element.replaceWith(child);
}

/// Copy attributes from sourceElement to targetElement, merging their values if the attribute is already present
Utils.mergeAttributes = function(sourceElement, targetElement) {
    var arr = sourceElement[0].attributes;
    for(var i = 0; i < arr.length; i++) {
        var item = arr[i];
        if(!item.specified)
            continue;

        var key = item.name;
        var sourceVal = item.value;
        var targetVal = targetElement.attr(key);

        if(sourceVal === targetVal)
            continue;

        var newVal = targetVal === undefined
            ? sourceVal
            : sourceVal + ' ' + targetVal;

        targetElement.attr(key, newVal);
    }
}

angular.module('test')
.directive('unwrap', function() {
    return {
        restrict: 'AE',
        templateUrl: 'unwrap.part.html',
        compile: function() {
            return function postCompile(scope, element, attr) {
                Utils.replaceWithChild(element);
            };
        }
    }; 
});
Philtre answered 14/12, 2014 at 13:5 Comment(3)
its not a good solution because replace deprecated for concept not feature , we usually don't have any css for the directive element then we dont see any effect of the primary elementBicarb
@Ali.MD There are cases where you want to decorate (read: add functionality to) some element but having it wrapped in another div would cause trouble. If you want to use multiple decorators, the html structure will change drastically and as a result you may get broken css or javascript.Philtre
A very good example would be a container component (think React).Simferopol
M
6

From GitHub:

Caitp-- It's deprecated because there are known, very silly problems with replace: true, a number of which can't really be fixed in a reasonable fashion. If you're careful and avoid these problems, then more power to you, but for the benefit of new users, it's easier to just tell them "this will give you a headache, don't do it".

-- AngularJS Issue #7636

replace:true is Deprecated

From the Docs:

replace ([DEPRECATED!], will be removed in next major release - i.e. v2.0)

specify what the template should replace. Defaults to false.

  • true - the template will replace the directive's element.
  • false - the template will replace the contents of the directive's element.

-- AngularJS Comprehensive Directive API

See also -- How to use the 'replace' feature for custom AngularJS directives?

Meagre answered 22/2, 2016 at 3:40 Comment(0)
H
5

I'd say it's a good thing that is has been removed because it prevents you from exposing inner workings of a directive (component) to the outside world. Look at your template as being a shadow DOM and compare your directive with normal HTML elements like a button You don't see all kinds of classes being added and styling being applied to those elements either when you hover or click them. It's all 'hidden' inside. Because support for shadow DOM is somewhat limited at the moment it is kind of a workaround but it already enables you to be future proof.

Hewlett answered 26/5, 2015 at 14:32 Comment(2)
There are issues with ways of coding forms and with SVG elements that needs replace. I agree however, it's harder to debug.Alga
I had to learn this the hard way.Perpetrate

© 2022 - 2024 — McMap. All rights reserved.