how to add Blockly workspace and toolbox to angular 2 project

2,265 views
Skip to first unread message

Abhigya jain

unread,
Jun 14, 2017, 9:25:15 AM6/14/17
to Blockly
Hi,

Can anyone please tell me how to integrate blockly into a angular 2 project ?
what commands/files/setup do i need ?

Regards
Abhigya


Cory Diers

unread,
Jun 14, 2017, 1:12:30 PM6/14/17
to blo...@googlegroups.com
Hi Abhigya,

So as a preface, I'm not exactly an Angular expert, but we have been working on a visually-impaired accessible version of Blockly, which uses Angular. The code for that can be found in our Github repo, and a simple example can be found here. The important bits are to make sure that you've included the core blockly files as outlined in our developer documentation. Then, in one of your Angular files, you'll want to define the div, toolbox, and make the call to Blockly.inject. You'll likely want all of that code in your AppComponent or some other fairly high-level class.

Note that the blind-acessible library for Blockly doesn't instantiate a full Blockly div, because it doesn't display the same way that core Blockly does, so it's a little different. But hopefully having some reference for a similar project will help.

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Cory Diers | Software Engineer | cory...@google.com | 

Abhigya jain

unread,
Jun 15, 2017, 2:15:37 AM6/15/17
to Blockly
Thanks Cory ! Will give it a look. Will get back in case of further queries.

Thanks


On Wednesday, 14 June 2017 22:42:30 UTC+5:30, Cory Diers wrote:
Hi Abhigya,

So as a preface, I'm not exactly an Angular expert, but we have been working on a visually-impaired accessible version of Blockly, which uses Angular. The code for that can be found in our Github repo, and a simple example can be found here. The important bits are to make sure that you've included the core blockly files as outlined in our developer documentation. Then, in one of your Angular files, you'll want to define the div, toolbox, and make the call to Blockly.inject. You'll likely want all of that code in your AppComponent or some other fairly high-level class.

Note that the blind-acessible library for Blockly doesn't instantiate a full Blockly div, because it doesn't display the same way that core Blockly does, so it's a little different. But hopefully having some reference for a similar project will help.
On Wed, Jun 14, 2017 at 6:25 AM, Abhigya jain <abhig...@gmail.com> wrote:
Hi,

Can anyone please tell me how to integrate blockly into a angular 2 project ?
what commands/files/setup do i need ?

Regards
Abhigya


--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Abhigya jain

unread,
Jun 16, 2017, 6:13:24 AM6/16/17
to Blockly
Hi Cory,

i am facing the following error while trying to integrate blockly with angular 2 :

Unhandled Promise rejection: Template parse errors:
'block' is not a known element:
1. If 'block' is an Angular component, then verify that it is part of this module.
2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("
<xml id="toolbox" style="display: none">
  <category name="UI Operation">
    [ERROR ->]<block type="load"></block>
    <block type="click"></block>
    <block type="doubleclick"></block>"): ng:///BlocklyModule/BlocklyComponent.html@14:4

Basically, angular is not able to recognize "<block>" as a valid tag . I have included the core blockly files as part of my project.

Any idea what am i missing ?

Cory Diers

unread,
Jun 20, 2017, 1:06:28 PM6/20/17
to blo...@googlegroups.com
Hi Abhigya,

So, "block" isn't a valid angular tag. If you're including the toolbox in your angular files, I imagine you're going to have to add the NO_ERRORS_SCHEMA to your component, because otherwise Angular's going to complain about it. Alternatively, you could set up your index file such that it loads Angular, then injects Blockly separately, something like:

document.addEventListener('DOMContentLoaded', function() {
   ng.platform.browser.bootstrap(blocklyApp.AppComponent);
});

var workspace = Blockly.inject('blocklyDiv',
      {toolbox: document.getElementById('toolbox')});

Though I've not tried that, and may be easier said than done, since it's not exactly the normal Angular flow. As a third option, you might be able to inject the XML without including it directly in a component's template, so Angular doesn't trip up on trying to parse it, but I have no idea how you might go about that.

To unsubscribe from this group and stop receiving emails from it, send an email to blockly+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Panagiotis Postantsidis

unread,
Jul 10, 2017, 4:07:13 AM7/10/17
to Blockly
Did you find an answer in this?
did it worked?

Abhigya jain

unread,
Jul 11, 2017, 3:27:57 AM7/11/17
to Blockly
Hi Panos,

What i have done is the following :
1) in my angular2 project i got the blockly package by running npm install blockly
blockly becomes a part of the node_modules
2) next, i place my Blocks.js and other js files inside node_modules itself because blockly js needs to be at the same folder level as the blockly package
3) next, in my index.html file, i have added the toolbox xml and blockly div:
<div id="blocklyDiv" style="height: 710px; width: 1000px;"></div>

<xml id="toolbox" style="display: none">
4) next, in my abc.component.ts file, i have added the following :
toolbox: any = {toolbox: document.getElementById('toolbox')};
_workspace = Blockly.inject('blocklyDiv', this.toolbox);

placing these components and stiching them together as required by angular2 , worked for me. i was able to get the workspace and toolbox on my project.

hope it helps.

Thanks
Abhigya

Panos Post

unread,
Jul 11, 2017, 5:12:53 AM7/11/17
to Blockly
Wow that looks great, i ll test it out thanks :D

Panos Post

unread,
Jul 11, 2017, 5:21:34 AM7/11/17
to Blockly
also what did u use as an import :)

Panos Post

unread,
Jul 11, 2017, 5:37:20 AM7/11/17
to Blockly
i did these steps but i am getting the error , 
Cannot read property 'inject' of undefined TypeError..
i am new in angular sorry if i dont get the basics ^_^

Panos Post

unread,
Jul 11, 2017, 6:52:06 AM7/11/17
to Blockly
https://stackoverflow.com/questions/40770447/include-and-use-npm-libraries-in-angular2-with-angular-cli
i tried this but i still get  this error 
TypeError: Blockly.inject is not a function TypeError: Blockly.inject ……}

Panos Post

unread,
Jul 11, 2017, 7:47:35 AM7/11/17
to Blockly
OK i think i injected the files correctly but i get the goog is undefined error
eferenceError: goog is not defined
    at eval (eval at webpackJsonp.11.module.exports (addScript.js:9), <anonymous>:27:1)
    at eval (<anonymous>)
    at webpackJsonp.11.module.exports (addScript.js:9)
    at Object.207 (colour.js?4ff6:1)
    at __webpack_require__ (bootstrap 7c0f67a…:52)
    at Object.644 (scripts.bundle.js:304)
    at __webpack_require__ (bootstrap 7c0f67a…:52)
    at webpackJsonpCallback (bootstrap 7c0f67a…:23)
    at scripts.bundle.js:1

Viktar Tserashchuk

unread,
Jul 11, 2017, 4:26:52 PM7/11/17
to Blockly
The issue is that webpack uses the eval function to add js bundles on the page, and Blockly uses strict mode ('use strict'). For that mode global variables, defined in the script, are not allowed to be used outside of that script.

So, after eval("'use strict'; var goog = ...") goog is not available.

My solution is adding the folowing lines at the end of blockly_compressed.js
this.Blockly = Blockly;
this.goog = goog;

That allows me to have properly defined Blockly and goog objects in the global scope.

вторник, 11 июля 2017 г., 14:47:35 UTC+3 пользователь Panos Post написал:

Panos Post

unread,
Jul 12, 2017, 3:39:52 AM7/12/17
to Blockly
Thank you, that helped a lot i made some progress
but still i get this error
Uncaught TypeError: Cannot read property 'options' of null
    at Object.Code.initLanguage (eval at webpackJsonp.9.module.exports (addScript.js:9), <anonymous>:462:15)
    at Code.init (eval at webpackJsonp.9.module.exports (addScript.js:9), <anonymous>:330:8)
    at ZoneDelegate.webpackJsonp.645.ZoneDelegate.invokeTask (zone.js:367)
    at Zone.webpackJsonp.645.Zone.runTask (zone.js:166)
    at ZoneTask.invoke (zone.js:420)

do you have any more of your javascript magic :D

Viktar Tserashchuk

unread,
Jul 12, 2017, 4:16:30 AM7/12/17
to Blockly
I am not sure what it is. It looks like you are trying to include some excess things.
I have managed to find Code.initLanguage in one of the Blockly demos (\demos\code\). Perhaps you should review the list of blockly files that you added to your bundles.

This is what I have in my angular-cli.json
      "scripts": [
          "../lib/Blockly/blockly_compressed.js",
          "../lib/Blockly/blocks_compressed.js",
          "../lib/Blockly/ru.js",
          "../lib/Blockly/javascript_compressed.js",
          "../lib/JsInterpreter/acorn_interpreter.js"
      ],

среда, 12 июля 2017 г., 10:39:52 UTC+3 пользователь Panos Post написал:

Panos Post

unread,
Jul 12, 2017, 4:17:17 AM7/12/17
to Blockly
OK guys i have no errors at all at blockly but there is no actual functionality 
plus the generating of the code from blockly to lua and xml(that i use), does not work
i have no errors in files in resources though, any ideas?
thanks in advance :D


Τη Τρίτη, 11 Ιουλίου 2017 - 10:26:52 μ.μ. UTC+2, ο χρήστης Viktar Tserashchuk έγραψε:

Viktar Tserashchuk

unread,
Jul 12, 2017, 5:05:18 AM7/12/17
to Blockly
Well, in that case without viewing the source code it's difficult to say where the issue is. Is the code available anywhere?

среда, 12 июля 2017 г., 11:17:17 UTC+3 пользователь Panos Post написал:

Panos Post

unread,
Jul 12, 2017, 5:12:28 AM7/12/17
to Blockly
the fuctionality that i want is in the demo file you said
demos/code/code.js this is the functionality that i want in my angular app,
or do i have to recreate all of this code in typescript?

Panos Post

unread,
Jul 12, 2017, 5:50:54 AM7/12/17
to Blockly
i dont know how but i hide the blocklyDIv with display:none and i add some height in the " <td height="800px" colspan=2 id="content_area">"
inside the demo.html and now i have the functionality of blockly 

Panos Post

unread,
Jul 12, 2017, 6:01:36 AM7/12/17
to Blockly
ok i have another problem though whenever i navigate through my angular app i have to refresh to show the blockly content area -.-

Panos Post

unread,
Jul 12, 2017, 7:31:32 AM7/12/17
to Blockly
i am injecting the xml with sanitizer but if i dont refresh it does not find the blockly div because i guess i placed it in the index.html

Panos Post

unread,
Jul 12, 2017, 8:15:00 AM7/12/17
to Blockly
so here is the new update, everything works and i inject both the div and the xml through the component 
but still for some reason when i navigate through the my app the  blockly content is "lost", and i have to refrest
not at all user friendly..
if you know a work around? because i tried to refresh forcefully only the view of the blockly component but nothing. -.-

Eric DC

unread,
Aug 18, 2017, 11:08:01 AM8/18/17
to Blockly
Hey guys, 

I'm a bit of a newb here when it comes to angular. I have my blockly working fine outside of angular, but trying to add it in to my project is going nowhere. I'm using angular 4 inside an asp.net core project. Can you give a bit more details of exactly what you put where to get this to work please? 

Would be greatly appreciated!! 

So far, in my component I have : 

import { Blockly } from 'blockly/blockly_compressed';
import { Blocks } from 'blockly/blocks_compressed';

I tried adding the following to the component as well, but it complains about document being undefined:

toolbox: any = { toolbox: document.getElementById('toolbox') };
 _workspace = Blockly.inject('blocklyDiv', toolbox);


THanks guys! 
Eric.

Frédéric Clement

unread,
Aug 19, 2017, 2:10:57 AM8/19/17
to Blockly
Hi,

I succeeded doing it in installing node-blockly and :

import Blockly from 'node-blockly/browser';

BUT :
I didn't find the way to create custom blocks this way, because, the build.py script dosn't seem to regenerate the browser.js file.

Fred

Eric DC

unread,
Aug 20, 2017, 2:16:09 PM8/20/17
to Blockly
Oh ok. What if you just manually added the custom blocks as JS in the HTML page itself? Would that work? That may be good enough for me lol



ad...@domaineseror.com

unread,
Aug 21, 2017, 1:56:01 AM8/21/17
to Blockly

Sure,

Would be great if the guy who made this (below) could give us the best practice :

Frédéric Clement

unread,
Aug 21, 2017, 5:51:41 AM8/21/17
to Blockly
Eric,

I think I found out how to do :


import { Component, OnInit } from '@angular/core';
import Blockly from 'node-blockly/browser';
import { ScriptService } from './scripts.service';

@Component({
selector: 'app-scripts',
templateUrl: './scripts.component.html',
styleUrls: ['./scripts.component.css']
})
export class ScriptsComponent implements OnInit {

constructor(private scriptservice: ScriptService) {
}
private code: string;
private xml: string;
private _scripts: any[];
private workspace;
private editor;
private _script_id: number;

toolbox = `<xml id="toolbox" style="display: none">
<category name="Logic">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
<block type="logic_negate"></block>
<block type="logic_boolean"></block>
<block type="logic_test"></block>
<block type="logic_test2"></block>
</category>
<category name="Loops">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
<field name="NUM">10</field>
</block>
</value>
</block>
<block type="controls_whileUntil"></block>
</category>
<category name="Math">
<block type="math_number"></block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
<block type="math_toto"></block>
</category>
<category name="Text">
<block type="text"></block>
<block type="text_length"></block>
<block type="text_print"></block>
</category>
</xml>`;


ngOnInit() {
const self = this;
this.workspace = new Blockly.Workspace();

this.editor = Blockly.inject('editor', {
toolbox: this.toolbox
});

this.scriptservice.loadScripts()
.then(
response => {
if (response != null) {
self._scripts = [];
for (const i in response) {
if (response[i] != null) {
const script = response[i];
self._scripts.push(
{
id: script.script_id,
text: script.script_name
}
);
}
}
}
}
);

const xml = Blockly.Xml.textToDom(localStorage.getItem('script'));
Blockly.Xml.domToWorkspace(xml, this.editor);
}

onScriptSelect(event) {
const self = this;
this.scriptservice.loadScript(event.id)
.then(
response => {
Blockly.getMainWorkspace().clear();
const xml = Blockly.Xml.textToDom(response);
Blockly.Xml.domToWorkspace(xml, this.editor);
self._script_id = event.id;
}
);
}

saveScript() {
const xml = Blockly.Xml.workspaceToDom(this.editor);
const xml_text = Blockly.Xml.domToText(xml);

localStorage.setItem('script', xml_text);
this.scriptservice.saveScript(this._script_id, xml_text);
}

clearScript() {
Blockly.getMainWorkspace().clear();
}

}





To compile your new blocks, you go to `node_modules/node-blockly`, and just type `yarn install`.

It works for me, hope it helps you

Eric DC

unread,
Aug 22, 2017, 10:39:11 AM8/22/17
to Blockly
Very interesting !! I will give that a go and let you know. Thanks for this !!

To unsubscribe from this group and stop receiving emails from it, send an email to blockly+unsubscribe@googlegroups.com.

Eric DC

unread,
Aug 22, 2017, 1:24:59 PM8/22/17
to Blockly
Ok stupid question lol : what's the ScriptService? I know I've seen this before, but what's in it ? Where can I get it ?

Thanks!
Eric.

CLEMENT Frédéric

unread,
Aug 23, 2017, 12:30:39 AM8/23/17
to blo...@googlegroups.com

Hi Eric,

it’s the service (of MVC model) written by myself and providing the datas.
Here is the code if that can help you :

import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/toPromise';

@Injectable()
export class ScriptService {
constructor(private http: Http) {}

loadScript(script_id) {
const token = localStorage.getItem('token');
const msg = {
header: {
method: 'load_script',
token: token
},
payload: {
script_id: script_id
}
};
return this.http.post('http://api.fredclement.fr:8080', JSON.stringify(msg))
.toPromise()
.then(
response => {
const rep = response.json();

if (rep.header.method === 'script') {
const hw = rep.payload.script;
return(hw);
} else {
alert('wrong reply ' + rep.header.method);
}
}
);
}

loadScripts() {
const token = localStorage.getItem('token');
const msg = {
header: {
method: 'load_scripts',
token: token
},
payload: {
}
};
return this.http.post('http://api.fredclement.fr:8080', JSON.stringify(msg))
.toPromise()
.then(
response => {
const rep = response.json();

if (rep.header.method === 'script_list') {
const hw = rep.payload.scripts;
return(hw);
} else {
alert('wrong reply ' + rep.header.method);
}
}
);
}

saveScript(script_id: number, xml: string ) {
const token = localStorage.getItem('token');
const msg = {
header: {
method: 'save_script',
token: token
},
payload: {
script_id: script_id,
script: xml
}
};
return this.http.post('http://api.fredclement.fr:8080', JSON.stringify(msg))
.toPromise()
.then(
response => {
}
);

}
}




Cordialement,


CLEMENT Frédéric
Tel : 06 61 03 27 21
Fax : 09 55 60 57 54
Mail : fred...@fredclement.fr

ad...@domaineseror.com

unread,
Aug 23, 2017, 12:42:30 AM8/23/17
to Blockly
Eric.



Le lundi 21 août 2017 07:56:01 UTC+2, ad...@domaineseror.com a écrit :<blockquote class="gmail_quote" style="margin:0;m

Eric DC

unread,
Aug 23, 2017, 7:19:52 AM8/23/17
to Blockly
Ahhh ok parfait je comprends!

Merci! :)



--

Vanessa P. Araya

unread,
Nov 14, 2017, 9:38:22 PM11/14/17
to Blockly
Thank you very much for the instructions! :)

Khushbu Yeole

unread,
Mar 9, 2018, 1:16:59 AM3/9/18
to Blockly
HI, I did the same code as you suggested but getting some error, "Cannot read property 'Workspace' of undefined"
I am doing blockly integration with angular 4 application. Not getting exactly what i am missing.
Please help me. 
Thanks in advance :)

Nithin Biliya

unread,
Jul 22, 2019, 12:05:00 AM7/22/19
to Blockly
I was able to setup with the below config mentioned below. I have also written a blog to explain this in details here - Integrate Google Blockly with Angular

install blockly with npm -

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']);
}
}


Regards,
Nithin
Reply all
Reply to author
Forward
0 new messages