Custom html with dynamic var

What I’m trying to do:
In the page ‘Form1’ I am receiving input addresses and generating the optimal routes for vehicles via python functions. This returns a string and after finding the solution it navigates to the page ‘Form3’ with this output as the variable ‘oplossing’. ( open_form(‘Form3’, oplossing=oplossing) )
Then Form3 is a customHTML page, it is connected with the google maps API and displays the routes of ‘oplossing’. In the customHTML page it has ’ var routes = … ’ where should be equal to ‘oplossing’.
However I can’t find a solution to pass the ‘oplossing’ variable to Form3 and use it in the customHTML at ’ var routes '.

What I’ve tried and what’s not working:
Tried almost everything I could think of

Code Sample:

# this is a formatted code snippet.

# paste your code between ``` 

A print screen of the part of html code and proof of working on the right:

So my ‘oplossing’ is exactly the same as the html var, only I can’t find a way to pass the value in the html in stead of first solving the problem with input, then copy paste it in the html and restart the app with the new html content.

Really hope someone has a solution for this, been trying forever now…

A possible solution could be the following:

  1. Create a hidden input field(s) on ‘Form3’

  2. Add a event listener to you’re hidden input fields, where you update you’re routes variable and possible update the map via the library you’re using to display the map?

  3. When opening the component you can use data binding to update the hidden input(s) on Form3

Some usefull resources data binding topic and data binding docs

Note: if the library doesn’t have a refresh method try refreshing the component, you can trigger that on the hidden input fields event listener via the anvil UI

Succes :wink:

Welcome to the Forum!

Here’s one alternative. Instead of:

you might try

open_form(Form3(oplossing=oplossing))

You’ll need to have Form3 imported above that point:

from Form3 import Form3

or something similar, and Form3’s __init__ function will need to accept that parameter.

At the moment, it looks like you’re using a static variable to define something that needs to be dynamic. There should be a way to update the variable for the map implementation your using. The docs should proved information about the available methods and how to use them. Find that method and call it with the updated variable.

A clone link would be very helpful here if you’re looking for more specific advice.

Thanks for your help, but this function is working fine.

Hi, thanks for your help. I indeed do not understand fully the explenation. The problem is that I use my API key multiple times, which is not very handy to share publicy. Can I give permissions specifically to you as Anvil staff?

it’s probably better to create a clone replacing your api key with "<API-KEY>"
that way others can also take a look and make suggestions

@stucork , Do you think displaying multiple routes with the data I have is also possible with the build in maps component. If so, this would maybe be a better pad to take.

I typically like to move things to python if i can help it

I’d suggest using the dynamic google maps loader

see here for what to add to native libraries:

Maps JavaScript API را بارگیری کنید  |  Google for Developers

Native Library code
<script>
  (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
    key: "API KEY",
    v: "weekly",
    // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
    // Add other bootstrap parameters as needed, using camel case.
  });
</script>

then i’d simplify your html for form 3 to be just

<div anvil-name="map" style="height: 400px; width: 100%;"></div>

finally i would move the logic to python

see code
from ._anvil_designer import Form3Template
from anvil import *
import anvil.js
from anvil.js.window import google
import random

colors = ["red", "blue", "yellow", "orange", "brown"]
routes = [
    {
        "origin": "amsterdam",
        "destination": "amsterdam",
        "waypoints": ["schiphol amsterdam", "schevingen", "rotterdam", "utrecht", "utrecht", "zwolle"],
        "travelMode": "DRIVING",
    },
    {
        "origin": "breda",
        "destination": "breda",
        "waypoints": ["eindhoven", "maastricht", "haaren", "venlo", "eindhoven"],
        "travelMode": "DRIVING",
    },
]

# ensure maps is loaded
maps = google.maps.importLibrary("maps")


class Form3(Form3Template):
    def __init__(self, oplossing=None, **properties):
        # Set Form properties and Data Bindings.
        self.init_components(**properties)
        self.map = google.maps.Map(
            self.dom_nodes["map"],
            {
                "center": {"lat": -34.397, "lng": 150.644},
                "zoom": 8,
            },
        )
        self.oplossing = oplossing or routes
        self.create_routes()

    def calculate_and_display_routes(self, service, renderer, route):
        waypoints = [{"location": location, "stopover": True} for location in route["waypoints"]]
        try:
            result = service.route(
                {
                    "origin": route["origin"],
                    "destination": route["destination"],
                    "waypoints": waypoints,
                    "optimizeWaypoints": True,
                    "travelMode": route["travelMode"],
                }
            )
            renderer.setDirections(result)
        except Exception as e:
            Notification(f"Direction request failed due to {e}", style="danger").show()

    def create_routes(self):
        for route in self.oplossing:
            service = google.maps.DirectionsService()
            renderer = google.maps.DirectionsRenderer(
                {
                    "map": self.map,
                    "polylineOptions": {
                        "strokeColor": random.choice(colors),  # Willekeurige kleur
                        "strokeOpacity": 0.7,
                    },
                }
            )
            self.calculate_and_display_routes(service, renderer, route)


you’ll probably need to add functionality like being able to clear the routes
but i don’t know the Maps api, you’d have to go look at the docs

clone:

1 Like

It worked, thanks a lot!

1 Like