4

I'm quite new to Svelte and still learning, but I'm kind of stuck at something that seems quite simple. I'm using Svelte and Svelte Material UI to create an app with a Material design look and feel.

I've started with a simple app bar and a slide-out menu. The problem I'm running in to is that in the Svelte Material UI docs, the button that causes the menu to slide in and out, is part of the same menu component: https://github.com/hperrin/svelte-material-ui/blob/master/site/src/routes/demo/menu.svelte

In my case, I would like the button to be part of my App-bar component and when I click that, the menu component should trigger to slide out (or in).

I've seen examples of how to pass properties (data) from one component to the other, but not how to trigger an event from one component to the other.

What I've tried:

  • exporting a function (seems to need the script to be a module, as described here)
  • exporting a boolean, and changing it from the outside (gives me an error I don't remember exactly what it was)

My code is as follows (using the "exporting a function" method):

App.svelte

<script>
  import TopAppBar, {Row, Section, Title} from '@smui/top-app-bar';
  import IconButton from '@smui/icon-button';
  import AppMenu, {Toggle} from "./AppMenu.svelte";

  let prominent = false;
  let dense = true;
  let secondaryColor = false;
</script>


<TopAppBar variant="static" {prominent} {dense} color={secondaryColor ? 'secondary' : 'primary'}>
  <Row>
    <Section>
      <IconButton class="material-icons" on:click={Toggle}>menu</IconButton>
      <Title>Test app</Title>
    </Section>
    <Section align="end" toolbar>
      <IconButton class="material-icons" aria-label="Print this page">account_circle</IconButton>
      <IconButton class="material-icons" aria-label="Bookmark this page">home</IconButton>
    </Section>
  </Row>
</TopAppBar>
<AppMenu></AppMenu>
<div>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque tellus libero, semper at lobortis at, congue sit amet lorem. Aliquam porttitor varius sagittis. In non lorem lorem. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque fringilla et nulla et tempus. Vestibulum pharetra tristique neque, non sodales massa dignissim vulputate. Sed eget leo tellus. Phasellus egestas gravida ante. 
</div>

Appmenu.svelte

<script>
  import Menu from '@smui/menu';
  import List, {Item, Separator, Text} from '@smui/list';
  import Button from '@smui/button';
  let menu;
  let clicked = 'nothing yet';
  let menustate = false;
</script>

<script context="module">
  export function Toggle(){
    menu.setOpen(open = !open)
  }
</script>

    <div style="min-width: 100px;">
      <Button on:click={() => menu.setOpen(true)}>Open Menu</Button>
      <Menu bind:this={menu}>
        <List>
          <Item on:SMUI:action={() => clicked = 'Cut'}><Text>Cut</Text></Item>
          <Item on:SMUI:action={() => clicked = 'Copy'}><Text>Copy</Text></Item>
          <Item on:SMUI:action={() => clicked = 'Paste'}><Text>Paste</Text></Item>
          <Separator />
          <Item on:SMUI:action={() => clicked = 'Delete'}><Text>Delete</Text></Item>
        </List>
      </Menu>
    </div>

Any help is appreciated

2 Answers 2

2

While using the context="module" approach would work, in your case you can easily just propagate the toggle function further up.

Let have MenuApp export the toggle function
In App use the bind syntax to bind your AppMenu to something (appMenu ?)
Call toggle on the object from your button

<IconButton class="material-icons" on:click={appMenu.toggle}>menu</IconButton>
Sign up to request clarification or add additional context in comments.

2 Comments

yes it is, but this works only if the components are relatively close of course
0

Your example should work. Here is a very simple example of exporting a function:

//C.svelte
<script context="module">
export function myFunc() {
  console.log("myFunc")
}
</script>

// App.svelte
<script>
  import {myFunc} from "./C.svelte"
</script>
<h1 on:click={myFunc}>click me</h1>

I think you should learn this kind of things with a very simple examples and later combine them to more complicated programs. I also recommend to leave external libraries away and first learn things with native elements, because those libraries hide things, change behaviors and even contains errors.

4 Comments

Well, it seems my approach is correct then, but my script (context="module") can't interact with the objects in the other script block. So I can't address menu. I'm building something and learning as I go along, so ditching the UI framework is not an option I'm afraid.
Variables in the context=”module” are not reactive, maybe you should use store in your case. More info: svelte.dev/docs#script_context_module
Here is a working example, but it feels like a bit hacky: svelte.dev/repl/efd9db7b3c9c41c4a60de48b58b8214a?version=3.24.1
I agree it feels hacky, I think you're correct in your remark about stores. I've read about it and it seems that is my usecase.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.