angularblocklyangular7

How do we import Blockly into an Angular 7 application?


I'm trying to use Blockly in an Angular 7 application but I'm unable to inject the Blockly editor.

I have downloaded the files from https://developers.google.com/blockly/guides/get-started/web and copied blockly_compressed.js into my src directory (and renamed it blockly.js). I then try to access Blockly from my component and get errors.

What I have tried:

import "../blockly.js"

Does not compile, gives "error TS2304: Cannot find name 'Blockly'."

import { Blockly } from '../blockly'

Compiles, but gives the following error when the app is opened in a browser:

ERROR TypeError: _blockly__WEBPACK_IMPORTED_MODULE_4__.Blockly.inject is not a function

Adding a blockly.d.ts file with the following:

export namespace Blockly {
    export function inject(div: string, config: any): void;
}

Gives the same error as above.

Any suggestions on what else I could try?


Solution

  • I was able to setup with the config mentioned below -

    install blockly with npm -

    npm install git://github.com/google/blockly.git#1.20190419.0
    

    included below files in scripts section of angular.json file -

        "scripts": [
          "node_modules/blockly/blockly_compressed.js",
          "node_modules/blockly/blocks_compressed.js",
          "node_modules/blockly/msg/js/en.js",
          "src/assets/blockly/custom_blocks.js"
        ]
    

    added below lines in my component html file -

      <div id="blocklyDiv" style="width: 100%; height: 100%"></div>
      <xml id="toolbox" style="display: none">
        <category name="Control" colour="120">
          <block type="controls_if"></block>
          <block type="controls_repeat_ext" disabled="true"></block>
        </category>
        <category name="Text" colour="230">
          <block type="text"></block>
          <block type="text_print"></block>
        </category>
        <category name="Custom" colour="360">
          <block type="begin"></block>
          <block type="move"></block>
          <block type="end"></block>
        </category>
      </xml>
    

    angular will throw error at this point saying it does not recognise the blockly tags. So need to use NO_ERRORS_SCHEMA in the module or can represent the toolbar XML as a string in the component TS file and use it to inject blockly.

    my component TS file -

    import { Component, OnInit } from '@angular/core';
    import { ActivatedRoute, Router } from '@angular/router';
    import { ProgramService } from '../services/program.service';
    import { IProgram } from '../models/program';
    
    declare var Blockly: any;
    
    @Component({
      selector: 'app-program-create',
      templateUrl: './program-create.component.html',
      styleUrls: ['./program-create.component.scss']
    })
    export class ProgramCreateComponent implements OnInit {
      title: string;
      programName: string;
      program: IProgram;
      workspace: any;
    
      constructor(
        private route: ActivatedRoute,
        private programService: ProgramService,
        private router: Router
      ) {
        this.title = 'Create Visual Program';
        this.route.params.subscribe(params => {
          this.programName = params['programName'];
          this.program = this.programService.getOne(this.programName);
          if (!this.program) {
            this.program = {
              name: this.programName,
              xmlData: null
            };
          }
          console.log(
            'creating/editing the program - ',
            JSON.stringify(this.program)
          );
        });
      }
    
      ngOnInit() {
        this.workspace = Blockly.inject('blocklyDiv', {
          toolbox: document.getElementById('toolbox'),
          scrollbars: false
        });
    
        if (this.program.xmlData) {
          this.workspace.clear();
          Blockly.Xml.domToWorkspace(
            Blockly.Xml.textToDom(this.program.xmlData),
            this.workspace
          );
        }
      }
    
      saveProgram(): void {
        this.program.xmlData = Blockly.Xml.domToText(
          Blockly.Xml.workspaceToDom(this.workspace)
        );
        console.log('saving the program - ', JSON.stringify(this.program));
        this.programService.upsertOne(this.program);
        this.router.navigate(['listProgram']);
      }
    }
    

    I have written an article explaining this in details here - Integrate Google Blockly with Angular