retejs / rete

JavaScript framework for visual programming
https://retejs.org
MIT License
9.86k stars 647 forks source link

Cannot read property 'style' of null #265

Closed Armaldio closed 5 years ago

Armaldio commented 5 years ago

I'm using vue cli 3 to generate the project.

Then my component:

<template>
  <div id="rete" class="node-editor"></div>
</template>

<script>
import Rete from 'rete';
// import ConnectionPlugin from 'rete-connection-plugin';
import VueRenderPlugin from 'rete-vue-render-plugin';

import CustomNodeComponent from './CustomNodeComponent.vue';
import CustomControlComponent from './CustomControlComponent.vue';

const container = document.querySelector('#rete');
const editor = new Rete.NodeEditor('demo@0.1.0', container);
editor.use(VueRenderPlugin);

class MyComponent extends Rete.Component {
  constructor() {
    super();
    this.data.render = 'vue';
    this.data.component = CustomNodeComponent;
    this.data.props = {};
  }
}

class MyControl extends Rete.Control {
  constructor() {
    super();
    this.data.render = 'vue';
    this.data.component = CustomControlComponent;
    this.data.props = {};
  }
}

const myComponent = new MyComponent();
editor.register(myComponent);
const myControl = new MyControl();
editor.register(myControl);

export default {
  name: 'Flow',
  mounted() {
  },
};
</script>

<style scoped lang="scss">
</style>

On launch, I'm not getting anything rendered, and get

image

The error appear to be at line 15 of my code

L15         -> const editor = new Rete.NodeEditor('demo@0.1.0', container);
rete.esm.js -> _this.view = new EditorView(container, _this.components, _assertThisInitialized(_this));
rete.esm.js -> _this.container.style.overflow = 'hidden';
iKlsR commented 5 years ago

I had this exact issue Saturday when I picked up this library since it's been a minute since I have used Vue so fairly new to this whole babel webpack thing and also first time using the cli (vue ui is super cool as well). The issue is that the element isn't ready when the script runs that portion of code. My solution might not be the best or correct but what worked for me is to your functionality into either an await call somewhere or perform this somewhere inside mounted() {}

My setup currently looks like this

<template>
    <div id="rete" v-show="visible" ref="rete"></div>
</template>
export default {
    methods: {
        async init() {
            // perform all initialization here
            let container = this.$refs.rete
        }

        mounted() {
            this.init();
        }
    }
}

To keep your single file component clean I would also recommend doing something like <script src="./Rete.js"></script> instead of chucking all your js inside as it can get unwieldy fast.

Note that I put async init, this is to make sure you can make await calls inside the function as you might need to do so when creating components.

This is just one part however and you will probably run into https://github.com/retejs/rete/issues/247 right after.

To fix that as well add @babel/plugin-transform-regenerator": "^7.0.0" and babel-polyfill": "^6.26.0" to your dependencies and follow the instructions in this comment https://github.com/retejs/rete/issues/247#issuecomment-459411540.

To continue documenting what I went through to get this working, also make sure that your rete div has at least the explicit height set for its style or it won't be visible.

I would also recommend sticking to pure javacript for writing your js, adding typescript introduces a slew of issues so if you want to get something up and running without a bunch of fiddling don't branch off.

Ni55aN commented 5 years ago

rete element doesn't exist when the querySelector calling. All initial operations with HTML elements in template must by performed in mounted(). Moreover, querySelector is a bad practive for Vue.js - use a $refs

iKlsR commented 5 years ago

@Ni55aN I was going to suggest the refs method but I'm still reading up on it. Also it's a bit hard for a newbie like me to grok the layout of the examples in the retejs repo since these are done dynamically. Could you make a simple barebones example based on a new vue cli project with the best practices? The threejs example on codesandbox is also a bit heavy I fear.

Armaldio commented 5 years ago

Thanks @iKlsR and @Ni55aN for this great explanation!

Moved all my stuff to mounted, but now facing

image

Also, already fixed the #247

iKlsR commented 5 years ago

Seems to me that would be on your end in your custom component, maybe try commenting out lines/chunks until you see what's not getting set.

Armaldio commented 5 years ago

The custom component is really minimal so I doubt that

<template>
  <p>control</p>
</template>

<script>
export default {
  name: 'control',
};
</script>
iKlsR commented 5 years ago

Ok would be hard to say without seeing your code.

Armaldio commented 5 years ago

Here is the repo: https://github.com/Armaldio/flow

iKlsR commented 5 years ago

@Armaldio You needed a super("component_name") call in your custom component. Not sure how that trickled down to vue stuff but it looks like you missed it in your repo because you seem to be using it in the snippet you posted. I'm also new to this :). I would also suggest maybe having an explicit data() {} in your export function.

I recommend looking through the rete repositories when using stuff to see what the author does, the documentation is pretty sparse but the code is super readable.

Ni55aN commented 5 years ago

eslint-disable-next-line is evil :) It hints that you missed super(name). The parameters emitter, key is redundant, super class require name only

Ni55aN commented 5 years ago
class MyComponent extends Rete.Component {
  constructor() {
    super("My component");
    this.data.render = 'vue';
    this.data.component = CustomNodeComponent;
    this.data.props = {};
  }
}
Armaldio commented 5 years ago

@iKlsR Yeah, it's in the snippet but did't worked (at least empty). I've also tried adding something to it, because I saw it took a string but that didn't made it.

Also, I'm mostly following the doc but it seems vue integration is missing infos and switching between native and vue render confuse me: https://rete.js.org/#/docs/plugins/vue-render

@Ni55aN I know ^^' just trying to setup my thing with different tries.

Everything finaly work without any errors, but nothing is renderer. I hope to sort this out quickly

Ni55aN commented 5 years ago

Parent of #rete element should have a sizes (and editor.view.resize() of course)

Ni55aN commented 5 years ago

https://rete.js.org/#/docs/components

Armaldio commented 5 years ago

All parents have fixed size as well as #rete but no luck https://github.com/Armaldio/flow/blob/master/src/components/Flow.vue

Ni55aN commented 5 years ago

obviously, since you have no nodes

Test (dont forget async mounted())

    editor.addNode(await myComponent.createNode({}));
Armaldio commented 5 years ago

Wonderfull that worked!

Thank you all for the quick support, really appreciate 🙏

On a side note, while well made, the docs seems to miss some infos. I think it culd be really usefull to like, show the code, on the example (https://rete.js.org/#/examples/basic) page

Issue can be closed, thank again