Reading Blockly blocks from a database

855 views
Skip to first unread message

Dominik Birtić

unread,
Mar 4, 2019, 2:29:49 AM3/4/19
to Blockly
Hello!

I've been trying and wondering if it's possible to read blocks and use them in your own Blockly workspace. For example, you make your own block and save it in a database, is there any way to use that block without attaching a script to a HTML and reading your block from there? I'm using node.js, mongoDB and mongoose for this and so far I haven't been able to make it work. Also I'd like to ask if anyone know how exactly are custom blocks read from the JavaScript file.

Cheers!

Dominik Birtić

Coda Highland

unread,
Mar 4, 2019, 8:37:10 AM3/4/19
to blo...@googlegroups.com
You still have to execute Javascript, but it doesn't have to be in a .js file that you load in a <script> tag -- you could have a TEXT field in your database containing JS code that you then eval().

You could also make a backend Node.js script that fetches JS from the database and serves it up, then use something like <script src="get_blocks?name=custom_block"></script>.

/s/ Adam

--
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.

Amber B

unread,
Mar 4, 2019, 8:49:08 AM3/4/19
to Blockly
To add a few things onto Coda's post:

2. As for including custom blocks, you would generally need to include the block definitions in their own JS file and then manually include that file wherever you include your other Blockly code.

Coda Highland

unread,
Mar 4, 2019, 8:51:32 AM3/4/19
to blo...@googlegroups.com
Huh. That seems... excessive? I don't quite understand what problem you were attempting to solve there. Are you specifically trying to run Blockly on the backend? The solution I was talking about is for running Blockly on the frontend and using Node.js to serve content from the backend, which I had assumed (possibly incorrectly) was the OP's use case.

/s/ Adam

--

Amber B

unread,
Mar 4, 2019, 8:58:17 AM3/4/19
to Blockly
Oh, I thought you meant as in actually running Blockly on the backend. It would generally be better to load up the XML from the backend while running Blockly on the frontend -- I had misread the OP as specifically not wanting to do that for some reason and was trying to figure out the best way to make that work for them.

Dominik Birtić

unread,
Mar 5, 2019, 10:25:05 AM3/5/19
to Blockly
Thank you Amber and Coda!

The thing what I'm doing is this, I'm starting up a node.js server which is connected to the mongoDB. The home page is Blockly. What I want to do is read Blockly block on backend (I already did that) and serve those blocks to the frontend. I'm not trying to write blocks in javascript file and then serve that file in a <script src="my_custom_blocks.js"> in HTML. I want to read custom blocks from the database and load them into the frontend. I tried that thing that Coda said with eval() but it didn't work or I used it wrong.

So, I want to load custom blocks from the database when I start my server, serve the read data to the frontend.

Coda, I haven't tried this "<script src="get_blocks?name=custom_block"></script>", what are you saying I should do with this?

Amber B

unread,
Mar 5, 2019, 1:10:35 PM3/5/19
to Blockly
Ahh, hrm. Yeah, we use a CDN file with our js for these purposes... I would expect the `eval()` to work if you have Blockly loaded properly and are getting the block definitions as text appropriately, though. Can we see a bit more of the code setup you have here? Are you running the eval() after already loading the core Blockly, or?

Coda Highland

unread,
Mar 5, 2019, 5:57:19 PM3/5/19
to blo...@googlegroups.com
My suggestion is to remember that web backends aren't restricted to only generating HTML and serving static scripts. You can generate absolutely anything you want.

From the client side, it's still going to look like the <script src="..."> tag that you said you don't want to do -- but the difference is that you're not going to be writing the code in a static JS file and serving it up, but instead the URL for the src attribute will point to a backend script in your Node.js project. That script outputs the necessary Javascript code for all of the blocks that you need. This script is free to query your database and do whatever else is necessary to write the code that defines the blocks. (Note that this generated code isn't going to be run server-side!)

/s/ Adam

--

Dominik Birtić

unread,
Mar 7, 2019, 5:19:18 AM3/7/19
to Blockly
router.get('/',function(req, res){
// opens the blockly index.html
res.sendFile(path.join(__dirname + '/index.html'));
// query which finds all blocks inside collection
Block.find({}).select('content -_id').exec(function(err, blocks){
if(err){
console.log(err);
}
else {
// iterates through custom blocks in db and shows them in the console
blocks.map(block => {
console.log(block);
//eval(block);
});
}
});
});
The code above is the code that I use for finding my custom blocks in MongoDB. I'm not exactly sure how to use eval() properly.

Coda, when you say "but instead the URL for the src attribute will point to a backend script in your Node.js project" do you mean that in the index.html file where I load Blockly I should write <script src="url of my server and point to the JS script...">? I'm not exactly sure how should I take your advice. I'd be very grateful if you would give me more info about this. I understood it like this: I should point to the script in my project which loads blocks from the database and give it to the html which uses Blockly.
Please correct me if I'm wrong.

Amber, in the code above I'm serving the index.html which loads Blockly and then I'm reading from the database. It could be that I'm missing something or doing something wrong but it still doesn't work the way that I want it to work. I commented eval() out because I tested something.

Thanks again for your time and advice!

Uwe K

unread,
Mar 7, 2019, 8:21:56 AM3/7/19
to Blockly
Return the html file for this route and your blocks for a different route. Load the second route from your html file, either through a script tag or through fetch.

Don't use eval on the server. On the server you want to send the block code to clients. The client is where you want to interprete that code. That's what eval is for.

Coda Highland

unread,
Mar 7, 2019, 9:43:42 AM3/7/19
to blo...@googlegroups.com
Okay, you're using Express... It probably will look something like this.

router.get('/blocks', function(req, res) {
  Block.find({}).select(whatever).exec(function(err, blocks)) {
    res.send(blocks.join('\n'));
  });
});

Inside your index.html, then, all you need is <script src='/blocks'></script> after the tags that load Blockly.

/s/ Adam

Dominik Birtić

unread,
Mar 8, 2019, 8:27:55 AM3/8/19
to Blockly
Okay, I still get the same error "TypeError: Unknown block type: test_block blockly_compressed.js:1369:28" and I wrote the code that you said I should write.

<!-- Blockly headers -->
<script src="../../appengine/storage.js"></script>
<script src="../../blockly_compressed.js"></script>
<script src="../../blocks_compressed.js"></script>
<script src="../../javascript_compressed.js"></script>
<script src="../../msg/js/en.js"></script>
<script src="../../python_compressed.js"></script>
<script src='/load_blocks'></script>
index.html

router.get('/load_blocks', function(req, res){
// query which finds all blocks inside collection
Block.find({}).select('content -_id').exec(function(err, blocks){
var strings = [];
if(err){
console.log(err);
}
else {
res.send(blocks);
}
});
});
app.use('/load_blocks', router);
app.js

​Am I doing something wrong?

I'm grateful for the time and effort that you use to help me and guide me!

Uwe K

unread,
Mar 8, 2019, 10:06:43 AM3/8/19
to Blockly
Check if the load_blocks document contains the definition of test_block. If you open the network tab of your browser's dev tools and reload the page, there should appear an entry for the load_blocks request. Does the response contain your block definition?


Coda Highland

unread,
Mar 8, 2019, 4:06:27 PM3/8/19
to blo...@googlegroups.com
I don't know what you've got stored in your db. Can you show an example of what that request gives back? It might just not be organized in the way that Blockly needs.

/s/ Adam

--

Dominik Birtić

unread,
Mar 11, 2019, 5:44:26 AM3/11/19
to Blockly
I attached a picture of response on my page where I use Blockly where I should load custom blocks.

  1. _id
    :
    5c7cf353c6456c1a70496ec2
  2. content
    :
    "Blockly.Blocks['test_block'] = { init: function() { this.app..."
  3. name
    :
    "test_block"
This is how I made documents that hold blocks. I put block definition and its functionality into the "content" field. I copied both from the JavaScript file that I previously used for custom blocks. When I search blocks I only search for "content" field so that "_id" and "name" fields are not given to the client.

Thank you both for your time and your help!
response to the client.PNG

Uwe K

unread,
Mar 11, 2019, 8:37:51 AM3/11/19
to Blockly
You're almost there. You're sending a JSON file, but the <script> tag tells the browser to interpret the file content as javascript code. Try res.send( blocks.content) on the server side.

Coda Highland

unread,
Mar 11, 2019, 9:21:30 AM3/11/19
to blo...@googlegroups.com
Not quite: `res.send(blocks.content)` won't work either. That would just return undefined, since the structure is an array of objects.

`res.send(blocks.map(block => block.content).join('\n'))` will do the job.

/s/ Adam

On Mon, Mar 11, 2019 at 7:37 AM Uwe K <seldom...@gmail.com> wrote:
You're almost there. You're sending a JSON file, but the <script> tag tells the browser to interpret the file content as javascript code. Try res.send( blocks.content) on the server side.

--

Dominik Birtić

unread,
Mar 12, 2019, 5:38:02 AM3/12/19
to Blockly
Thank you guys so much!

It works now how it should. I'm very thankful.
Reply all
Reply to author
Forward
0 new messages