question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Instantiate only one directive playing a particular role

See original GitHub issue

We need to provide a way to tell the compiler not to instantiate a directive when there is another, more specialized, directive that does the same job.

Imagine we have a default value accessor directive used by forms.

@Directive({
  selector: '[ng-control]'
})
class DefaultValueAccessor {}

Now, let’s add a more specialized value accessor that can handle checkboxes.

@Directive({
  selector: "input[type=checkbox][ng-control]
})
class CheckeboxValueAccessor {}

In the following template I would like the first input to use DefaultValueAccessor, and the second input to use CheckeboxValueAccessor.

<input type="text" ng-control="name">
<input type="checkbox" ng-control="isAmerican">

Unfortunately, the second input will end up having two value accessors. So this approach does not work.

What we have to do right now is to write mutually exclusive selectors that look like this:

@Directive({
  selector: 'input:not([type=checkbox])[ng-control],textarea[ng-control]'
})
class DefaultValueAccessor {}

Even though this approach is not elegant, it sort of works when one person/team provides a set of directives. If, however, I would like to add a third-party value accessor, I will end up having the same problem: I will have two value accessors created for the same element.

Proposal 1

Have a mechanism to tell the compiler that all value accessors play the same role. So the compiler can instantiate only one for each element. The compiler can take the last directives from the list of directives that matches a element.

@Directive({selector: '[ng-control]', role: 'valueAccessor')
class DefaultValueAccessor{}

@Directive({selector: 'some custom stuff', role: 'valueAccessor')
class CustomValueAccessor{}

const directives = [DefaultValueAccessor, CustomValueAccessor];

If CustomValueAccessor matches the element, DefaultValueAccessor will not be instantiated.

We can also try to unify this concept with exportAs, because the role and the local name should always match.

Proposal 2

Have a generic mechanism for a directive to specify a compile-time predicate to determine if it should be instantiated.

function lastValueAccessor(thisBinding, bindings) {
  // find thisBinding in bindings, and make sure that this is the last value accessor.
}

@Directive({selector: '[ng-control]', predicate:lastValueAccessor)
class DefaultValueAccessor{}

@Directive({selector: 'some custom stuff', predicate:lastValueAccessor)
class CustomValueAccessor{}

This can be useful for other scenarios. For example, if you want to make sure that the dom structure matches some required shape. This may not work with Dart transformers.

@mhevery @tbosch @jeffbcross

Issue Analytics

  • State:open
  • Created 8 years ago
  • Reactions:25
  • Comments:8 (6 by maintainers)

github_iconTop GitHub Comments

5reactions
JohannesHoppecommented, Sep 25, 2016

Any plans for Angular 2.1? Plain HTML5 forms are just painfull (e.g. <input type="date">) Right now we are more or less forced to use some third-party libraries to fill the gap…

5reactions
awerlangcommented, Mar 1, 2016

I like the first proposal, but I think we can make it more inclusive. What about:

import {DefaultValueAccessor} from 'angular2/common';

@Directive({
  selector: "input[type=checkbox][ng-control]",
  override: DefaultValueAccessor
})
class CheckeboxValueAccessor extends DefaultValueAccessor {}

Rules:

  • Build an hierarchy from the directives that matches the element, based on the override field.
  • If there are two or more overrides, disallow and throw?
  • Do not attach to the element all directives that have been overriden
Read more comments on GitHub >

github_iconTop Results From Across the Web

Instantiate component from a directive - angular - Stack Overflow
1 Answer 1 · Günter Zöchbauer, your solution helps to get access for existed component. Is it possible to create a new instance...
Read more >
Call a function of an Instantiated object's script - Unity Forum
I'm creating program that procedurally generates a galaxy. In this program I'm trying to get the calculated temperature of a planet, but in ......
Read more >
Instantiating Prefabs at run time - Unity - Manual
This technique allows you to blow up a robot into many pieces, with just one line of code, which replaces the original GameObject...
Read more >
Chapter 3. C++ Instantiation #pragma Directives - TechPubs
A member function name (for example, A<int>::foo) can be used as an argument for a #pragma instantiate directive only if it refers to...
Read more >
How to spawn an object in Unity (using Instantiate)
The most basic version of the Instantiate function takes a single ... But, once you've created your objects in play mode, how can...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found