Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manipulating DOM imperatively #120

Open
janat08 opened this issue Jun 15, 2020 · 11 comments
Open

Manipulating DOM imperatively #120

janat08 opened this issue Jun 15, 2020 · 11 comments

Comments

@janat08
Copy link

janat08 commented Jun 15, 2020

How do you attach jquery or imperative widgets?

@janat08
Copy link
Author

janat08 commented Jun 16, 2020

I'm asking for onrendered hook.

@limemloh
Copy link
Member

limemloh commented Jun 16, 2020

There is no official api for this yet, but it can be done by declaring a component using a class extending Component.
You can use imperative code in the run method, which is given a very limited api for the parent and a destroyed future meant for cleaning up.

A small example of this is the TextComponent

class TextComponent extends Component<{}, {}> {
  constructor(private t: Showable) {
    super();
  }
  run(parent: DomApi, destroyed: Future<boolean>): Out<{}, {}> {
    const node = document.createTextNode(this.t.toString());
    parent.appendChild(node);
    destroyed.subscribe((toplevel) => {
      if (toplevel) {
        parent.removeChild(node);
      }
    });
    return { available: {}, output: {} };
  }
}

export function text(showable: Showable): Component<{}, {}> {
  return new TextComponent(showable);
}

@janat08
Copy link
Author

janat08 commented Jun 17, 2020

Judging by the domapi interface there's no way of passing info up to the parent, like inserted widgets interface?

@limemloh
Copy link
Member

I'm not entirely sure what you want to archive, but the api is for manipulations.
One way to pass information to a parent is as output, but that might not be what you want.
Another approach is to make a parent, which supplies it children with something else than the DOMapi, which is bit more work.

Could you be a bit more specific of what you would like to do?

@janat08
Copy link
Author

janat08 commented Jun 17, 2020

Use this widget
https://webtorrent.io/docs

@janat08
Copy link
Author

janat08 commented Jun 17, 2020

It creates a client that Id like to use.

@limemloh
Copy link
Member

limemloh commented Jun 17, 2020

I'm assuming you also want to use file.appendTo(elm),
The quick solution is to wrap the client code inside run.
Here is an example using one of the examples from WebTorrent:

class WebTorrent extends Component<{}, {}> {
  constructor() {
    super();
  }
  run(parent: DomApi, destroyed: Future<boolean>): Out<{}, {}> {
    // Container element for files
    const elm = document.createElement("div");
    parent.appendChild(elm);
    var client = new WebTorrent()
    // torrentId could be given as argument
    client.add(torrentId, function (torrent) {
      var file = torrent.files.find(function (file) {
        return file.name.endsWith('.mp4')
      })
      // Use the container element for the files
      file.appendTo(elm)
    })
    destroyed.subscribe((toplevel) => {
      if (toplevel) {
        parent.removeChild(elm);
      }
      // removes the client when the component is remove
      client.destroy()
    });
    return { available: {}, output: {} };
  }
}

@janat08
Copy link
Author

janat08 commented Jun 18, 2020 via email

@limemloh
Copy link
Member

limemloh commented Jun 18, 2020

If it is changed based on some logic outside the component then you can provide the information to the constructor, otherwise you can just do the change inside run by manipulating elm

@janat08
Copy link
Author

janat08 commented Jun 19, 2020

Do you mean passing down a stream as a prop? How does that look like, I'm not familiar with using classes.

@limemloh
Copy link
Member

We hope to have a cleaner api for wrapping imperative code in the future without using classes, but until then:

class FileContainer extends Component<{}, {}> {
  constructor(private stream: Stream<File>) {
    super();
  }
  run(parent: DomApi, destroyed: Future<boolean>): Out<{}, {}> {
    ...
    // access the stream through `this`
    this.stream.subscribe((file)=> ...)
    ...
  }
}

function fileContainer(files: Stream<File>) {
  return new FileContainer(files);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants