Skip to main content

Getting started with Blockly

7. Save/load workspace

You now have a Blockly workspace. However, if you reload the page, you'll find that any blocks you've dragged into the workspace will disappear. Your users likely won't want their blocks to vanish, but you can fix this by saving the state of the workspace and loading it back in the next time they visit the site. For this codelab, we'll save the state of the workspace to local browser storage.

Add the save method

Open src/serialization.js. You'll set a unique storage key for this codelab. Then you'll add a function save which takes the Blockly workspace, exports its state to a JavaScript object, then saves that object to local storage.

Add the following code to the serialization.js file:

import * as Blockly from 'blockly/core';

const storageKey = 'getting-started-codelab/mainWorkspace';

/**
* Saves the state of the workspace to browser's local storage.
* @param {Blockly.Workspace} workspace Blockly workspace to save.
*/
export const save = function (workspace) {
const data = Blockly.serialization.workspaces.save(workspace);
window.localStorage?.setItem(storageKey, JSON.stringify(data));
};

Add the load method

When a user opens or reloads the page, the blocks in local storage should be loaded back into the workspace. The following load function handles this by checking for items in local storage and loading them into the workspace.

In the serialization.js file, add this code:

/**
* Loads saved state from local storage into the given workspace.
* @param {Blockly.Workspace} workspace Blockly workspace to load into.
*/
export const load = function (workspace) {
const data = window.localStorage?.getItem(storageKey);
if (!data) return;

// Don't emit events during loading.
Blockly.Events.disable();
Blockly.serialization.workspaces.load(JSON.parse(data), workspace, false);
Blockly.Events.enable();
};

Events

You may have noticed that the load function disables events from emitting while loading the workspace. Every change on the workspace, like dragging a block or connecting blocks, triggers an event. You can listen in to the event stream to run code when certain events happen.

For the load function, disabling events while loading will help prevent unexpected behavior, since some parts of Blockly listen to the event stream to know when to execute.

You can take advantage of the event stream to know when to call the save and load functions.

Add a Change Listener

In src/index.js, add the following import statement.

import {save, load} from './serialization';

Now, you'll add a change listener at the bottom of index.js to listen to the event stream. You'll also add a call to load outside of the change listener, so that your app finds the saved blocks on initial load.

In the code below, every time an event fires, this change listener will trigger and save the workspace.

load(ws);

// Every time the workspace changes state, save the changes to storage.
ws.addChangeListener((e) => {
save(ws);
});

This change listener is not yet complete, since there are some types of events that you shouldn't save after. UI changes (e.g. scrolling, zooming, or opening toolbox categories) change how the workspace looks but don't change the state of the blocks. Since we're only saving the blocks, we won't save after these types of events.

Here's the full change listener code, including the call to load outside of the change listener:

load(ws);

// Every time the workspace changes state, save the changes to storage.
ws.addChangeListener((e) => {
// UI events are things like scrolling, zooming, etc.
// No need to save after one of these.
if (e.isUiEvent) return;
save(ws);
});

To learn more about the events stream, see the Events documentation.

Testing the changes

Now, test the code. Add some blocks, then reload the page. The workspace should still contain the blocks you added.