1

I have a simple schematic running that proves how schematics work as described in https://angular.io/guide/schematics-for-libraries

My next step is to do something relevent to my project using the schematic - What I want is to add a directive to all of my HTML angular templates in my application

For example if there is a HTML file that has content like this

<input name="input" [(ngModel)]="input" />

after running the schematic (adds the directive)

<input appInput name="input" [(ngModel)]="input" />

From the documentation or otherwise, I am unable to see how to loop through all the files and make this change to each file. Are there any examples/pointers for this use case?

I know ng update does it for migration from NG7 => NG8 to add this to the @ViewChild /** TO DO - static flag is mandatory */ but not able to narrow down the code for this.

Basically, what can I do here to get a handle to all the HTML files

export function appInputs(_options: any): Rule {
  return (tree: Tree, _context: SchematicContext) => {
  console.log('schematic called');
  const workspaceConfig = tree.read('/angular.json');
  // convert workspace to string
  if (workspaceConfig) {
    const workspaceContent = workspaceConfig.toString();

    // parse workspace string into JSON object
    const workspace: experimental.workspace.WorkspaceSchema = JSON.parse(workspaceContent);
    console.log(workspace);
  }

  return tree;
};
}
user2789284
  • 751
  • 1
  • 11
  • 28

2 Answers2

0

Even if the question is old, this could be a piece of answer : https://blog.angular.io/schematics-an-introduction-dc1dfbc2a2b2

Basically, read the Tree interface API, there are methods you can use, I hope it may help :

tree.getDir(options.sourceDir)
          .visit(filePath => {
Alain Boudard
  • 768
  • 6
  • 16
0

Yes this is not documented well.

Unfortunately you cannot use a JavaScript AST tool like jsdom to modify Angular templates. The serialize(..) method will mangle your directives, events, methods and tag annotation - or just fail to serialize.

That said, you can still use a JS AST tool like jsdom to locate the file position, offset location, of the elements you wish to modify and then use the schematics recorder to make those modifications.

Something like

    // get the length -- from the begining to where the attr should go
    const INPUT_OFFSET = '<input'.length;

    const buffer = tree.read(FILE_PATH);
    const content = buffer.toString();

    // make sure you explictly tell fsdom to use includeNodeLocations
    const dom = new FSDOM(content, { includeNodeLocations: true });
    const elements = dom.window.document.querySelectorAll('input');

    // use the schematics tree recorder to update
    // we wont use the serialize(..) method of fsdom
    const recorder = tree.beginUpdate(FILE_PATH);

    elements.forEach(element => {
      // get the location in the source HTML of the element
      const locations = dom.nodeLocation(element);

      if (locations) {
        // add the directive, keep the white space on either side
        recorder.insertLeft(locations.startOffset + INPUT_OFFSET, ' appInput ');
      }
    });


    // all updates are committed without interfering with each offset
    tree.commitUpdate(recorder);

    return tree;
Martin
  • 15,820
  • 4
  • 47
  • 56