Warm tip: This article is reproduced from stackoverflow.com, please click
asp.net-core blazor c# javascript typescript

Using JSInterop to pass object to JavaScript results in empty object

发布于 2020-03-27 10:29:33

Within ASP.Net Core I'm trying to build basic bindings for Google Maps from C# code. Using JSInterop I can successfully pass strings to JavaScript functions but when I try to pass more complex objects, the object appears empty in the JavaScript function.

I've partly followed this tutorial and modified it to use Google Maps rather than Bing Maps.

As in the tutorial, I've found TypeScript definitions for Google Maps to help code the bindings.

I have the following razor file, which should load a map when the user clicks the button:

@page "/sitemapper"
@inherits SiteMapperBase

<h3>Map</h3>

<div id="map" style="position: relative; width: 100%; height: 70vh;"></div>

<button class="btn btn-primary" @onclick="@OpenMap">Click me</button>

@code {
void OpenMap()
{
    LoadMap();
}
}

The corresponding .razor.cs file has the following LoadMap method:

        protected async Task LoadMap()
        {
            LatLng center = new LatLng(40.417268, -3.696050);
            MapOptions options = new MapOptions("map", center, 8);
            await JSRuntime.InvokeAsync<Task>("loadMap", options);
        }

The C# classes in the above code are defined here:

public class MapOptions
    {
        public string elementId;
        public LatLng center;
        public int zoom;

        public MapOptions(string elementId, LatLng center, int zoom)
        {
            this.elementId = elementId;
            this.center = center;
            this.zoom = zoom;
        }
    }

    public class LatLng
    {
        public double lat;
        public double lng;

        public LatLng(double latitude, double longitude)
        {
            lat = latitude;
            lng = longitude;
        }
    }

On the JavaScript/TypeScript side, I have defined the following interfaces, which match the C# classes:

interface GoogleMapOptionsInterface {
    center: GoogleMapLatLngInterface,
    zoom: number,
    elementId: string
}

interface GoogleMapLatLngInterface {
    lat: number,
    lng: number
}

Finally, I have a GoogleTsInterop.ts file, with my TypeScript code:

/// <reference path="types/index.d.ts" />
/// <reference path="interfaces/GoogleMapsInterfaces.ts" />

let googleMap: GoogleMap;

class GoogleMap {
    map: google.maps.Map;

    constructor(options: GoogleMapOptionsInterface) {
        console.log("constructor");
        var mapElement = document.getElementById(options.elementId);
        this.map = new google.maps.Map(mapElement, {
            center: options.center,
            zoom: options.zoom
        });
    }
}

function loadMap(options: GoogleMapOptionsInterface) {
    new GoogleMap(options);
}

When I try run this, the map does not load, and looking in the browsers debugger shows me that the options object in the loadMap(...) function is an empty object (see screenshot) (sorry, I don't have enough reputation to put the image in directly).

If I change my code I can successfully pass a string with the following: await JSRuntime.InvokeAsync<Task>("loadMap", "test");. However I want to pass the object.

Is there a way to do this? What am I doing wrong? Thanks

Questioner
galen
Viewed
133
Vogel T. 2019-07-04 00:40

Can you pass it as a JsonResult or JSON string?

MapOptions options = new MapOptions("map", center, 8);
JSRuntime.InvokeAsync<Task>("loadMap", Json(options));

or

MapOptions options = new MapOptions("map", center, 8);
var result = new JavaScriptSerializer().Serialize(options);
JSRuntime.InvokeAsync<Task>("loadMap", result);