Can't update palette nodes/links with the gojs-angular 2 wrapper

According to the documentation :

Additionally, PaletteComponent no longer supports skipsPaletteUpdate or modelChange properties. As GoJS Palettes are read-only by default, their models should not be changing based on user input. Instead, if you need to update their node/link/model data, update their @Input properties (immutably, of course).

So I have tried this :

public ngOnInit(): void {
  
    // initialize palette for nodes
    this.state = produce(this.state, draft => {

      this._processDesignerService.processDesignerMetadata.paletteNodes.forEach(el => {
        el.color1 = 'white';
        el.desiredSize = '120 60';
      });
      draft.paletteNodeData = this._processDesignerService.processDesignerMetadata.paletteNodes;

    });


It works the first time my diagram is displayed. If I move away from the page and come back, I get this exception:

TypeError: Cannot assign to read only property ‘color1’ of object ‘[object Object]’

I guess I’m not updating the palette nodes as I should… What is the correct way ?

So that’s your initial setting of Palette data – what code are you using to update it later?

Or are you saying if you refresh the browser you get that error? I’m not quite sure what you mean by “If I move away from the page and come back”

Move away as in navigate to a different route within my application. If I navigate back to the diagram component page, I get the error. If I land on that page for the first time, it works fine (so a refresh does work indeed).

My initial palette data is coming from the server and is loaded with that code you are seeing, but I modify it slightly before assigning to draft.paletteNodeData.

I’m not sure here, since it seems like processDesigner.paletteNodes (the object that is apparently read only) is outside the scope of our standard gojs-angular-basic sample, so I’m just shooting in the dark right now…

  • Have you tried setting color1 and desiredSize outside the produce call?
  • Have you tried other lifecycle hooks, like ngAfterViewInit?
  • If you take the service out of the equation and just hard-code some dummy data for paletteNodes, then do the produce call, do you get the same error? If so, the issue may be service-related

I have tried all of the above. Same results, except third bullet point. That works indeed if I do :

const paletteNodeData = [
      {
        "label": "End",
        "key": "End",
        "color2": "grey",
        "figure": "Ellipse",
        "taskDefinitionCode": null
      },
      {
        "label": "System Task",
        "key": "StepSystemTask",
        "color2": "green",
        "figure": "RoundedRectangle",
        "taskDefinitionCode": null
      }
    ];

    paletteNodeData.forEach(el => {
      el['color1'] = 'white';
      el['desiredSize'] = '120 60';
    });

    // initialize palette for nodes
    this.state = produce(this.state, draft => {

      draft.paletteNodeData = paletteNodeData;

Of course I don’t want to do that and I want to keep using data coming from my service. However the following gives me the error mentioned above if land on that page after visiting it already.

 const src = _.clone(this._processDesignerService.processDesignerMetadata.paletteNodes);
    src.forEach(el => {
      el.color1 = 'white';
      el.desiredSize = '120 60';
    });

    // initialize palette for nodes
    this.state = produce(this.state, draft => {
      draft.paletteNodeData = src;

It does not make sense to me. Cloning the service data should make it a new object (and it’s not even readonly anyway). It seems the produce method makes it readonly afterwards. But indeed this is likely to be related to immer rather than go-js

Yes, this is likely an issue with the service or immer, neither of which I can claim to be an expert with

It’s certainly outside my area of expertise, but maybe if you send me your service file I can look it over and see if anything stands out. You can do that here or via email if you’re more comfortable with that

Thanks for willing to help but it was a silly mistake I made and i was so focused on the new way of modifying data (produce) that I didn’t see it…

const src = _.clone(this._processDesignerService.processDesignerMetadata.paletteNodes);

should be

const src = _.cloneDeep(this._processDesignerService.processDesignerMetadata.paletteNodes);