Why is `replace` property deprecated in AngularJS directives?

JavascriptAngularjsAngularjs Directive

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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.

Solution 2 - Javascript

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);
            };
        }
	}; 
});

Solution 3 - Javascript

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 -- https://stackoverflow.com/questions/22497706/how-to-use-the-replace-feature-for-custom-angularjs-directives/35519198#35519198

Solution 4 - Javascript

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsbleonView Question on Stackoverflow
Solution 1 - JavascriptLessQuesarView Answer on Stackoverflow
Solution 2 - JavascriptMarkosView Answer on Stackoverflow
Solution 3 - JavascriptgeorgeawgView Answer on Stackoverflow
Solution 4 - JavascriptBas SlagterView Answer on Stackoverflow