Open manekinekko opened 8 years ago
{%
set classes = [
'field',
'field--name-' ~ field_name|clean_class,
'field--type-' ~ field_type|clean_class,
'field--label-' ~ label_display,
'comment-wrapper',
]
%}
{%
set title_classes = [
'title',
label_display == 'visually_hidden' ? 'visually-hidden',
]
%}
<section{{ attributes.addClass(classes) }}>
{% if comments and not label_hidden %}
{{ title_prefix }}
<h2{{ title_attributes.addClass(title_classes) }}>{{ label }}</h2>
{{ title_suffix }}
{% endif %}
{{ comments }}
{% if comment_form %}
<h2 class="title comment-form__title">{{ 'Add new comment'|t }}</h2>
{{ comment_form }}
{% endif %}
</section>
<section [class]="classes">
<div *ngIf="comments && !label_hidden">
{{ title_prefix }}
<h2 [class]="title_class" >{{ label }}</h2>
{{ title_suffix }}
</div>
<!-- "comments" would be a separate component -->
<angular2-comment-list [comments]="comments"></angular2-comment-list>
<div *ngIf="comment_form">
<h2 class="title comment-form__title">{{ 'Add new comment'| t }}</h2>
<!-- "form" would be a separate component -->
<angular2-comment-form></angular2-comment-form>
</div>
</section>
Twig variables classes
and title_classes
would typically be set inside a component Class (in the JavaScript world).
A quick and dirty solution would be...
1) include the Twig.js library :
<script src="/core/assets/vendor/angular2/twig-0.8.7.js"></script>
<script src="/core/assets/vendor/angular2/twig-custom.js"></script>
We also include a twig-custom.js
which contains the reimplementation of some drupal custom filters such as clean_class
.
2) update this portion of code: https://github.com/angular/angular/blob/36a423fac8866e8a849cf3ab1c4a15d08b0ccb8c/modules/angular2/src/compiler/template_normalizer.ts#L42-L43
with something like:
//...
var _isTwig = template.templateUrl.endsWith('.twig');
if(_isTwig) {
templateContent = twig({
data: templateContent
}).render(new directiveType.runtime());
}
//...
This code simply checks if the current loaded template is a Twig file (from the extension), and runs the twig
API to compile the template using the directive/component context.
3) use an Angular 2 component as usual:
@Component({
selector: 'angular2-comment-field',
templateUrl: '/core/themes/classy/templates/field/field--comment.html.twig',
// ...
})
class DrupalCommentField {
// Twig template variables
private comments: string = 'comments';
private label_hidden: string = 'label_hidden';
private field_name: string = 'field_name_1';
private field_type: string = 'field_type_1';
private label_display: string = 'label_display_1';
// Drupal Template Function: attributes.addClass()
private attributes = {
addClass: (args) => {
return ` class="${ args.join(' ') }" `;
}
}
// Drupal Template Function: title_attributes.addClass()
private title_attributes = {
addClass: (args) => {
return ` class="${args.join(' ')}" `;
}
}
constructor() {}
}
This is the default (unmodified!) Twig template:
<section{{ attributes.addClass(classes) }}>
{% if comments and not label_hidden %}
{{ title_prefix }}
<h2{{ title_attributes.addClass(title_classes) }}>{{ label }}</h2>
{{ title_suffix }}
{% endif %}
{{ comments }}
{% if comment_form %}
<h2 class="title comment-form__title">{{ 'Add new comment'|t }}</h2>
{{ comment_form }}
{% endif %}
</section>
DONE!
With these 3 steps, we were able to load a .twig template, compile it using the Twig.js library and pass basic variable to the template.
See this commit for more code https://github.com/manekinekko/angular2-drupal/commit/b22aacbe79b52cc5bea6225dca5b7679abaf3d57
comments
and comment_form
are the rendered HTML code representing the DOM structure. We need to figure out how we can replace those kind of variables with actual Angular 2 components, ideally without touching the template!. Otherwise, we'll have to substitute those variables {{ comments }}
with some CSS selectors like <comments></comments>
.attributes.addClass()
for instance.label_display == 'visually_hidden' ? 'visually-hidden'
. It needs to be a ternary expression: label_display == 'visually_hidden' ? 'visually-hidden' : ''
Angular 2 comes with a built-in HTML parser. We need to be able to plug in custom parsers, like the Twig one.
That should not be an issue. What is not clear in my head is if the twig and angular templates could be made to be semantically equivalent.
We need to re-implement Drupal functions and filters used in Twig.
should be easy.
Some variables such as comments and comment_form are the rendered HTML code representing the DOM structure. We need to figure out how we can replace those kind of variables with actual Angular 2 components, ideally without touching the template!. Otherwise, we'll have to substitute those variables
{{ comments }}
with some CSS selectors like<comments></comments>
.
In angular you can insert dom like this: <div [innerHTML]="comments"></div>
We need to migrate the sanitization work from NG1 to NG2.
Some variables such as comments and comment_form are the rendered HTML code representing the DOM structure. We need to figure out how we can replace those kind of variables with actual Angular 2 components, ideally without touching the template!.
This is the scariest/most complex part. This is where Drupal's "Render API" enters the picture.
The Render API allows you to write "render arrays", which are nested associative arrays (PHP lingo for the "map" or "dictionary" data structure in CS) that allow developers to declaratively indicate which HTML should be rendered. Why?
A bit more high-level context about our Render API which I think will help you relate to it more easily:
@RenderElement
in Drupal's code base.I'm very curious to see how you're going to tackle this!
In angular you can insert dom like this:
<div [innerHTML]="comments"></div>
We need to migrate the sanitization work from NG1 to NG2.
@mhevery aren't we going to loose control over those components if we just insert their DOM?
This is the scariest/most complex part. This is where Drupal's "Render API" enters the picture.
@wimleers Thanks for all the details. This is gonna be useful when digging inside Drupal world which is going to be my next step.
@manekinekko Let me know whenever you're stuck on something, whether it's code or understanding Drupal stuff. Happy to jump on a call/hangout too.
In angular you can insert dom like this:
<div [innerHTML]="comments"></div>
We need to migrate the sanitization work from NG1 to NG2. @mhevery aren't we going to loose control over those components if we just insert their DOM?
Yes, innerHTML
will not be allowed to compile the directives. Use DynamicComponentLoader
for that instead.
@mhevery In order to use the DynamicComponentLoader
we need to have a defined component. However, Drupal uses render arrays to compose complexe HTML. So some inner Twig variables are compiled and rendered dynamically, I don't think they have their own Twig template. Am I right @wimleers
For instance (see diagram below), I am able to use the comment.html.twig
template inside the Angular2 component CommentsBlock
which renders fine. But the {{ user_picture }}
Twig variable gets substituted with a dynamically rendered HTML. So in order to Have a UserPicture
Angular2 component, and compose complex UI with Angular, we need that template! I am now trying to figure out how we could get this done.
@mhevery In order to use the DynamicComponentLoader we need to have a defined component.
that is correct. Just make a component on the fly.
var Component = ng.Component({template: someHtml}).Class({constructor: function() {{});
NOTE: Selector can not have spaces or >
in it.
@mhevery I am using this selector #block-baked-content > article > div.node__content > section
and It seems to works fine, in beta.1
@tbosch We should throw an error. I am not sure what exactly happens, perhaps we match on section
?
I added Tobias to this private repo.
I have been trying to incorporate Twig into my Angular 2 CLI project, using @angular/cli": "1.0.0-rc.2
I came across @manekinekko project https://github.com/manekinekko/angular2-twig but have not had any luck incorporating it into my CLI project. Has anyone experimented with that?
A rendered comment (like all rendered output in Drupal) can be heavily customized by themes. For example, comment.html.twig can be overridden with entirely different markup. In this project, we would like to explore two different architectural approaches:
Dedicated Drupal thread https://github.com/acquia/js-exploration/issues/4