Skip to content
This repository has been archived by the owner on Feb 22, 2018. It is now read-only.

Feature Request: Add templates for NgDirectives or a NgComponent non-shadow dom option #367

Closed
demike opened this issue Dec 19, 2013 · 17 comments

Comments

@demike
Copy link
Contributor

demike commented Dec 19, 2013

When trying to port the angular-ui bootstrap components to dart I stumbled uppon a problem with nested directives / components and css selectors.

For example the progress and bar directives in angular-ui bootstrap:

<progress max="100">
  <bar type="'warning'" value="29"></bar>
  <bar type="'danger'" value="2"></bar>
</progress>

in angular-ui this works fine (without shadow dom)

Using a NgComponent for 'progress':
First problem: can't create shadow dom because the Html5 progress element exists.
Ok rename it to 'prog'

The real problem is how the inserted content is handled in shadow dom:
Image

Like depicted in the image above it breaks css selectors like

.progress .bar-danger {
  ...
}

and that holds true for nesting NgComponent > NgDirective and
NgComponent > NgComponent.

This can make working with angular.dart (actually with shadow dom, angular.dart is cool ;) ) a pain.
So my request would be to add 'template' and 'templateUrl' to
NgDirective or to add an option to NgComponent to replace the
hosting dom element with the given template instead of using shadow dom.

edit:
Is there some kind of transclude option for NgComponent that does not place the nested elements in the shadow dom <content></content> i am not aware of?

@mhevery
Copy link
Contributor

mhevery commented Jan 9, 2014

What you are asking for is to have NgComponents which don't use shadow dom. This would require that we reimplement shadow dom as transclusion. Not sure I would like to go that route. This is a ShadowDOM issue and should be taken up with ShadowDOM folks.

@ghost ghost assigned jbdeboer Jan 9, 2014
@jbdeboer
Copy link
Contributor

jbdeboer commented Jan 9, 2014

The Shadow DOM solution to the broken CSS selectors is the use pseudo elements. I've hacked up a ng-pseudo directive that should solve your problem. Please take a look at it and let me know.

jbdeboer@4d05f3c

In the Todo app's "TypeComponent", we are using ng-pseudo to tag a span as 'x-text'. demo/todo/todo.dart line 116

In the light DOM's css file, we can now say: li:hover todo-type::x-text, demo/todo/todo.css line 51

@demike
Copy link
Contributor Author

demike commented Jan 9, 2014

@jbdeboer thanks for pointing me to the ng-pseudo directive. It is very handy and I will definitely use it in the future.
But in this case I do not want to modify the bootstrap.css file.
In this special case I can solve my css problem by applying the "progress" class to the original element (not the created one in shadow dom).

But what remains is the nested component question.
@mhevery NgComponents with an option:

@NgComponent(
  shadowdom: true // true/false (default: true)
);

would be useful, but I can understand your concerns

But there is one feature of NgComponent that is definitely missing for me:

Lets say I want to develop a new full calendar component, that has sub components like
a complex configuration bar and a component day.

example:

<mycalendar>
    <day ng-repeat="day in month">{{day.content}}</day>
    <mycalendarconfigbar></mycalendarconfigbar> 
</mycalendar>

With the current NgComponent all of the child component are exposed to "document" via the <content></content> element.
So the one feature I am missing is to transclude the nested content instead of putting it in <content></content>
A possible solution would be to add an optional attribute "transclude" to the content tag
or as an option to NgComponent:

<!-- mycomponenttemplate.html -->

<div class="mycomponent">
  <!--  some cool things go here -->
   <content transclude>
   </content>
</div>

or

@NgComponent(
  transclude: true // (default: false)
);

if this attribute is available replace the <content> tag with the content of "mycomponent".
So that nested components really stay in the created shadow dom of "mycomponent" and do not
get exposed via <content>

@zoechi
Copy link
Contributor

zoechi commented Jan 21, 2014

@demike I do this by

in mycomponent

  List<dom.Node> nodes = new List<dom.Node>();
  @override
  void onShadowRoot(dom.ShadowRoot shadowRoot) {
    nodes.addAll((shadowRoot.querySelector('#content') as dom.ContentElement).getDistributedNodes());
    nodes.forEach((n) => n.remove());
  }

And on the tag in the mycomponent template where I want to have them transcluded to I add ng-bind-nodes="ctrl.nodes"

@NgDirective(
  selector: '[ng-bind-nodes]',
  publishAs: 'ctrlx' // conflicts with my-component
)
class NgBindNodesDirective {
  dom.Element _element;
  MyComponent _myComponent;
  Scope _scope;
  Compiler _compile;
  Injector _injector;

  NgBindNodesDirective(this._element, this._myComponent, this._scope, this._compile, this._injector);

  @NgOneWay('ng-bind-nodes') set nodes(var nodes) {
    print(nodes);
    if(nodes == null) {
      return;
    }
    _element.nodes.clear();
    nodes.forEach((dom.Node node) {
      _element.nodes.add(node.clone(true));
    });

    BlockFactory template = _compile(_element.nodes);
    Block block = template(_injector, _element.nodes);
  }
}

Works fine so far. Now also when the trancluded nodes contain bindings/directives.

@angular-dart-ui
Copy link

I'm trying to migrate an existing angularjs app to angular.dart, however, the fact that every component creates a shadow dom makes working with angular.dart a real pain. In addition, testing nested components is very hard.
The original proposal of demike is absolutely interesting. It would be very good to have 'template' and 'templateUrl' in the NgDirective. Essentially, it would be perfect to have the NgDirective equivalent to the one of angular.js.

@Pajn
Copy link

Pajn commented Feb 14, 2014

I would also like an option to override shadow dom for certain components.
My use case is an element where multiple components can stuff buttons, I
would then want to space out the buttons using flexbox. Using shadow dom,
this is impossible.

@mhevery
Copy link
Contributor

mhevery commented Feb 19, 2014

Seems like @NgComponent should support shadowDom:false flag.

@mhevery mhevery reopened this Feb 19, 2014
@zoechi
Copy link
Contributor

zoechi commented Feb 19, 2014

or lightDOM true as in Polymer but AFAIR they are going to remove it (or have already)

@etsuo
Copy link

etsuo commented Feb 20, 2014

@mhevery - I agree.

I use bootstrap and I'd like to implement a component that reduces this mess (per input element!):

<div ng-class="{'form-group':1, 'has-feedback': 1, 'has-success': 
          cmp.lastNameOk == cmp.OK, 'has-error': cmp.lastNameOk == 
          cmp.ERROR}">
          <label class="col-sm-2 control-label">Last Name:</label>
          <div class="col-sm-5">
            <input id="lastName" class="form-control" type="text" ng-
                            model="cmp.lastName" 
                            ng-keyup="cmp.validateLastName(cmp.lastName)" required 
                            maxlength="20">
            <span ng-class="{'glyphicon': cmp.lastNameOk > 0, 
                            'form-control-feedback': cmp.lastNameOk > 0, 
                            'glyphicon-ok': cmp.lastNameOk == cmp.OK, 
                            'glyphicon-remove': cmp.lastNameOk == cmp.ERROR}">
              </span>
          </div>
</div>

to something more like:

<nifty-input args, etc... >

so that I can stamp out forms more consistently and quickly... but the shadowdom / boostrap combo denies me this glory.

There are a number of cases, however, where I benefit from the encapsulation that the shadowdom provides... the choice would really be nice.

@mhevery
Copy link
Contributor

mhevery commented Feb 20, 2014

Anyone wants to take a stab at it? This one is a hard one. :-)

@ismail-codar
Copy link

This is very important feature. Because otherwise (with shadowdom option) it is very difficult to use twitter bootstrap, semantic-ui like existing css frameworks with angulardart.

@etsuo
Copy link

etsuo commented Mar 12, 2014

Ran into another NgComponent shadow dom limitation... jquery ui... I wish I knew enough about the implementation to help you out with this @mhevery :-)

@jbdeboer
Copy link
Contributor

@codelogic is working on this.

@ufoscout
Copy link

lol! milestone? 👏

@etsuo
Copy link

etsuo commented Mar 19, 2014

nice! thanks @codelogic!!!!

@ismail-codar
Copy link

Good news on this morning! Thanks.

@antonmoiseev
Copy link

Looking forward to see any progress on this item and try it out. Developing UI for Dart web apps never was easy, but after deprecating applyAuthorStyles it's not even fun anymore. The reality is we are not Google and can't afford investing a lot of resources developing Web Components. Twitter Bootstrap (and similar ones) was the way to go, but things start fall to pieces.

It's hard to communicate to the management that we completely switch the direction we are working on every couple of weeks. Yesterday it was Shadow DOM, today we rely on applyAuthorStyles and carefully make sure our CSS doesn't cross Shadow DOM boundaries, tomorrow we don't know what to do.

@mhevery mhevery assigned mhevery and unassigned jbdeboer Apr 16, 2014
jbdeboer added a commit that referenced this issue Apr 22, 2014
jbdeboer added a commit that referenced this issue Apr 22, 2014
jbdeboer added a commit that referenced this issue Apr 22, 2014
jbdeboer added a commit that referenced this issue Apr 23, 2014
jbdeboer added a commit that referenced this issue Apr 30, 2014
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests