3

I'm attempting to do something that I feel is pretty basic: I have a pulldown, and I'd like the onchange event for that pulldown to cause the program to fetch some data from the backend based on the user's input. (And then, you know, give the user more options based on the first thing they picked. Really simple, and seems like I ought to have been able to find an easy way to do this.)

Full code for this minimal (failing) example is at: https://github.com/djmcmath/broken-yew

But the relevant bit, which doesn't behave correctly, is below:

  • The view function renders, delightfully, an iterated list. I pass in a callback, so it knows what to do on the "onchange" event.
  • The callback gets executed, which makes me very happy. But it isn't calling the Msg::GetData. This compiles, which is nice, but it doesn't work, which is less nice.

I've spent, I'm ashamed to admit, several weeks of my spare time fighting with this. I think it has something to do with scopes and lifetimes. I think that the way I'm making this compile -- by cloning the context and using "move" disconnects it from the actual context that I need to make this work. But every variation on the theme that I've been able to find in examples and references complains about scope or lifetimes.

Thanks in advance for the help.

    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool { 
        match msg {
            Msg::GetData(value) => {
                log::info!("Start 'fetch' with user-selected value: {}", value);
                ctx.link().send_future(async {
                    match fetch_markdown("url_shortened_for_clarity").await {
                        Ok(md) => Msg::SetMarkdownFetchState(FetchState::Success(md)),
                        Err(err) => Msg::SetMarkdownFetchState(FetchState::Failed(err)),
                    }
                });
                false
            },
            Msg::SetMarkdownFetchState(fetch_state) => {
                let mut wr = WebReturn { term_id: 0, dow: 0, dep_time_num: 0 };
                match fetch_state {
                    FetchState::Success(s) => { wr = serde_json::from_str(&s).expect(&format!("Poorly formatted JSON! {}", s).to_string()); },
                    FetchState::Failed(f) => { log::info!("Fetch failed: {}", f); },
                    FetchState::NotFetching => {},
                    FetchState::Fetching => {}
                };
            
                log::info!("term_id (3) : {}, dep_time_num (12000) : {}, and dow (3) : {}", wr.term_id, wr.dep_time_num, wr.dow);
                true
            }
        }
    }

    fn view(&self, ctx:&Context<Self>) -> Html {
        let ctx_link = ctx.link().clone();
        let my_callback: Callback<String> = Callback::from(move |value: String| {
            let val_as_num = value.parse::<i32>().unwrap_or(0);
            log::info!("Returned value: {}", val_as_num);
            ctx_link.callback(|val_as_num: i32| Msg::GetData(val_as_num));
        });
        
        html! {
            <div>
                { self.render_list(&self.props.term_list, my_callback) }
            </div>
        }
    }
Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
djmcmath
  • 97
  • 5

1 Answers1

3

This line does not "call back" to your component, it creates a callback and then doesn't call it:

ctx_link.callback(|val_as_num: i32| Msg::GetData(val_as_num));

You need to instead call .send_message() in your callback or, better yet, create your original callback with .callback():

let my_callback = ctx_link.callback(|value: String| {
    let val_as_num = value.parse::<i32>().unwrap_or(0);
    log::info!("Returned value: {}", val_as_num);
    Msg::GetData(val_as_num)
});
kmdreko
  • 42,554
  • 6
  • 57
  • 106
  • 1
    Wow. Yeah. That's it. Thank you. I'd upvote the answer, but I don't have enough reputation to do so. – djmcmath May 25 '22 at 01:50
  • 1
    @djmcmath If this answers your question, you should accept the answer by clicking the checkmark next to it. See [what should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers) – Aiden4 May 25 '22 at 03:57