0

I'm trying to extend Angular's default component templates into customized ones we can use for our team. I've read through/followed a few tutorials, though none seem to do what I'm trying to accomplish. Anyway, I think I've gotten to a place where things should mostly work, but I'm running into a "viewEncapsulation is not defined" error, which is a little bit vague. I've narrowed it down to the code I copied from @schematics/angular in the template:

import { Component, OnInit<% if(!!viewEncapsulation) { %>, ViewEncapsulation<% }%><% if(changeDetection !== 'Default') { %>, ChangeDetectionStrategy<% }%> } from '@angular/core';
//                                 ^^^ HERE ^^^
@Component({
  selector: '<%= selector %>',<% if(inlineTemplate) { %>
  template: `
    <p>
      <%= dasherize(name) %> works!
    </p>
  `,<% } else { %>
  templateUrl: './<%= dasherize(name) %>.component.html',<% } if(inlineStyle) { %>
  styles: []<% } else { %>
  styleUrls: ['./<%= dasherize(name) %>.component.<%= styleext %>']<% } %><% if(!!viewEncapsulation) { %>,
  encapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } if (changeDetection !== 'Default') { %>,
  changeDetection: ChangeDetectionStrategy.<%= changeDetection %><% } %>
})
export class <%= classify(name) %>Component implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

As I dug through the code in @schematics/angular, I decided the problem was probably coming from my schema.json, but updating that seems to have no effect. Then I thought it might be the generated schema.js, but running npm run build doesn't seem to generate code to match the one I'm modeling.

How do I get my schema.js to update? If that isn't the problem, then how do I fix the viewEncapsulation error?

-- Files --

schema.json

{
    "$schema": "http://json-schema.org/schema",
    "id": "CricutSchematicsComponent",
    "title": "Cricut Design Space Component",
    "type": "object",
    "properties": {
        "path": {
            "type": "string",
            "format": "path",
            "description": "The path to create the component.",
            "visible": false
        },
        "project": {
            "type": "string",
            "description": "The name of the project.",
            "$default": {
                "$source": "projectName"
            }
        },
        "name": {
            "type": "string",
            "description": "The name of the component.",
            "$default": {
                "$source": "argv",
                "index": 0
            },
            "x-prompt": "What name would you like to use for the component?"
        },
        "inlineStyle": {
            "description": "Specifies if the style will be in the ts file.",
            "type": "boolean",
            "default": false,
            "alias": "s"
        },
        "inlineTemplate": {
            "description": "Specifies if the template will be in the ts file.",
            "type": "boolean",
            "default": false,
            "alias": "t"
        },
        "viewEncapsulation": {
            "description": "Specifies the view encapsulation strategy.",
            "enum": ["Emulated", "Native", "None", "ShadowDom"],
            "type": "string",
            "alias": "v"
        },
        "changeDetection": {
            "description": "Specifies the change detection strategy.",
            "enum": ["Default", "OnPush"],
            "type": "string",
            "default": "Default",
            "alias": "c"
        },
        "prefix": {
            "type": "string",
            "description": "The prefix to apply to generated selectors.",
            "alias": "p",
            "oneOf": [
                {
                    "maxLength": 0
                },
                {
                    "minLength": 1,
                    "format": "html-selector"
                }
            ]
        },
        "styleext": {
            "description": "The file extension to be used for style files.",
            "type": "string",
            "default": "css"
        },
        "spec": {
            "type": "boolean",
            "description": "Specifies if a spec file is generated.",
            "default": true
        },
        "flat": {
            "type": "boolean",
            "description": "Flag to indicate if a directory is created.",
            "default": false
        },
        "skipImport": {
            "type": "boolean",
            "description": "Flag to skip the module import.",
            "default": false
        },
        "selector": {
            "type": "string",
            "format": "html-selector",
            "description": "The selector to use for the component."
        },
        "module": {
            "type": "string",
            "description": "Allows specification of the declaring module.",
            "alias": "m"
        },
        "export": {
            "type": "boolean",
            "default": false,
            "description": "Specifies if declaring module exports the component."
        },
        "entryComponent": {
            "type": "boolean",
            "default": false,
            "description": "Specifies if the component is an entry component of declaring module."
        },
        "lintFix": {
            "type": "boolean",
            "default": false,
            "description": "Specifies whether to apply lint fixes after generating the component."
        }
    },
    "required": ["name"]
}

schema.ts

export interface Schema {
    /**
     * Specifies the change detection strategy.
     */
    changeDetection?: ChangeDetection;
    /**
     * Specifies if the component is an entry component of declaring module.
     */
    entryComponent?: boolean;
    /**
     * Specifies if declaring module exports the component.
     */
    export?: boolean;
    /**
     * Flag to indicate if a directory is created.
     */
    flat?: boolean;
    /**
     * Specifies if the style will be in the ts file.
     */
    inlineStyle?: boolean;
    /**
     * Specifies if the template will be in the ts file.
     */
    inlineTemplate?: boolean;
    /**
     * Specifies whether to apply lint fixes after generating the component.
     */
    lintFix?: boolean;
    /**
     * Allows specification of the declaring module.
     */
    module?: string;
    /**
     * The name of the component.
     */
    name: string;
    /**
     * The path to create the component.
     */
    path?: string;
    /**
     * The prefix to apply to generated selectors.
     */
    prefix?: string;
    /**
     * The name of the project.
     */
    project?: string;
    /**
     * The selector to use for the component.
     */
    selector?: string;
    /**
     * Flag to skip the module import.
     */
    skipImport?: boolean;
    /**
     * Specifies if a spec file is generated.
     */
    spec?: boolean;
    /**
     * The file extension to be used for style files.
     */
    styleext?: string;
    /**
     * Specifies the view encapsulation strategy.
     */
    viewEncapsulation?: ViewEncapsulation;
}
/**
 * Specifies the change detection strategy.
 */
export declare enum ChangeDetection {
    Default = "Default",
    OnPush = "OnPush"
}
/**
 * Specifies the view encapsulation strategy.
 */
export declare enum ViewEncapsulation {
    Emulated = "Emulated",
    Native = "Native",
    None = "None",
    ShadowDOM = "ShadowDom"
}

index.ts

import {
    Rule,
    // Tree,
    apply,
    url,
    applyTemplates,
    move,
    chain,
    mergeWith,
    externalSchematic
} from '@angular-devkit/schematics';
import { strings, normalize /*experimental*/ } from '@angular-devkit/core';
import { Schema as ComponentSchema } from './schema';

export function component(options: ComponentSchema): Rule {
    return chain([
        externalSchematic('@schematics/angular', 'component', options),
        // (tree: Tree) => {
        () => {
            const templateSource = apply(url('./files'), [
                applyTemplates({
                    classify: strings.classify,
                    dasherize: strings.dasherize,
                    name: options.name
                }),
                move(normalize(options.path as string))
            ]);

            return chain([mergeWith(templateSource)]);
        }
    ]);
}

Logan Waite
  • 423
  • 5
  • 12
  • What template files do you have in the `./files` folder? – Felix Lemke Aug 05 '19 at 21:09
  • Do you generate the template files from these files or from the angular component schematic? – Felix Lemke Aug 05 '19 at 21:09
  • I just copied them over from the angular component schematic. I didn't know you could generate template files. – Logan Waite Aug 05 '19 at 21:14
  • So you create the template files twice? One time using the external schematic and one time your own template files, which you copied over? – Felix Lemke Aug 05 '19 at 21:15
  • After you ran the `externalSchematic` function, the component files are already created in your tree. Then you are going to create them another time using your own template files. – Felix Lemke Aug 05 '19 at 21:17
  • Okay, so it sounds like I don't need to recreate the template files. Should I even use `externalSchematic`, or should I do something different? – Logan Waite Aug 05 '19 at 21:59
  • I copied the schema.js file over, so it was able to run and create my component, but it didn't keep any of the changes I had made, so obviously I'm doing something wrong. What would be the best way to do this? Or is that its own separate question? – Logan Waite Aug 05 '19 at 22:00
  • You do not have to copy any of the files. Neither from the angular repository nor your own build files. – Felix Lemke Aug 05 '19 at 22:32
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/197528/discussion-between-logan-waite-and-ngfelixl). – Logan Waite Aug 05 '19 at 23:42

0 Answers0