skip to Main Content

I have a Blazor server application. On one of my pages I have the standard setup:

MyPage.razor:

@page "/mypage"
<div>
    <!-- stuff here ... -->
</div>

@code {
    // stuff here ...
}

On this page, I am looping through a List like so:

<div>
    @foreach(MyData anData in ListOfMyData){
        // stuff here ...
    }
</div>

Within this loop, I want to create an image with the HTML canvas element based off the data within MyData.

<div>
    @foreach(MyData anData in ListOfMyData){
        <div>
            <canvas id="@anData.id" class="myDataImage"></canvas>
        </div>
    }
</div>

Within the @code section, I am injecting IJSRuntime:

@code {
    [Inject]
    IJSRuntime JSRuntime { get; set; }
}

And I have my JavaScript code in: MyApp/wwwroot/js/MyJavaScript.js

function drawImage(canvasID, data){
    let thisCanvas = document.getElementById(canvasID);
    thisCanvas.width = xxx;
    thisCanvas.height = xxx;
    let ctx = thisCanvas.getContext('2d');
    ctx.beginPath();
    // ... more here
}

"Individually", this all works, meaning:

  1. I have successfullly used IJSRuntime before with other custom JavaScript fuctions.
  2. The JavaScript I have works, as I have tested it in a "vanilla" HTML project.

What I am having trouble figuring out is how to call the JavaScript function from within the "HTML" section of my Blazor (.razor) page.

2

Answers


  1. Here is my sample code.

    enter image description here

    MyJavaScript.js

    window.drawImage = function (canvasID, data) {
        let thisCanvas = document.getElementById(canvasID);
        if (!thisCanvas) return "Canvas not found";
        thisCanvas.width = data.width;
        thisCanvas.height = data.height;
        let ctx = thisCanvas.getContext('2d');
        ctx.fillStyle = 'blue';
        ctx.fillRect(0, 0, data.width, data.height);
        return "Drawing completed";
    }
    

    MyData.cs

    namespace BlazorCanvasApp.Models
    {
        public class MyData
        {
            public string? Id { get; set; }
            public int Width { get; set; }
            public int Height { get; set; }
        }
    }
    

    MyPage.razor

    @page "/mypage"
    @using BlazorCanvasApp.Models
    
    <h3>Canvas Sample</h3>
    
    <div>
        @foreach (var anData in ListOfMyData)
        {
            <div>
                <canvas id="@anData.Id" class="myDataImage"></canvas>
                <p>@(drawResults.ContainsKey(anData.Id) ? drawResults[anData.Id] : "Drawing...")</p>
            </div>
        }
    </div>
    
    @code {
        [Inject]
        private IJSRuntime JSRuntime { get; set; }
    
        private List<MyData> ListOfMyData = new List<MyData>();
        private Dictionary<string, string> drawResults = new Dictionary<string, string>();
    
        protected override async Task OnInitializedAsync()
        {
            // Mock Data
            ListOfMyData.Add(new MyData { Id = "canvas1", Width = 200, Height = 100 });
            ListOfMyData.Add(new MyData { Id = "canvas2", Width = 150, Height = 150 });
    
        }
    
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                foreach (var anData in ListOfMyData)
                {
                    string result = await JSRuntime.InvokeAsync<string>("drawImage", anData.Id, anData);
                    drawResults[anData.Id] = result;
                }
                StateHasChanged(); 
            }
        }
    }
    

    Test Result

    enter image description here

    Login or Signup to reply.
  2. You should just wrap the js function in a private method and call it from the HTML. I mean, that is if I understood correctly that your issue is calling it from a DOM or a component?

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search