Question Blazor simple demo syntax errors

Pablo

Well-known member
Joined
Aug 12, 2021
Messages
62
Programming Experience
10+
Hi colleagues,
As cjard has advised me, I'm trying to learn Blazor as web development instead of MVC. I'm following this tutorial, but although I'm copying it literally, I can see a few syntax errors which I can't figure out how to solve in the Page I'm working on. I already added the TodoItem class to the project. I tried to run it and there were compiler errors.

Code of the page in question:
@page "/todo"

<PageTitle>Todo</PageTitle>

<h1>Todo (todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>
<input placeholder="Something to do" @bind="newTodo" />
<button @onclick="AddTodo">Add Todo</button>

@code {
    private string? newTodo;

    private List<TodoItem> todos = new();

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem( { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}

I attach a screenshot so you can see the underlined words that are NOT supposed to be errors, but the compiler sees them like so. As we can see, the words 'bind', 'onclick', and 'code' are marked. Why?
page.png


I would highly appreciate your help to solve these errors exposed here, and also if you know any better place where to learn Blazor.
Thanks in advance.
Pablo
 
Solution
You don't (well, there are ways of making it possible but..) put html markup in the code area of a Blazor page. In this situation you'd probably use blazor's built in validation - see Blazor University - Validation about making the todo item description "required"..

..but in a general sense in Blazor it's all about binding; if you want to enable some button when the age is above 21, then you do something more like putting the markup in the markup area of the page and bind its enabled-ness to a boolean property which is perhaps like

C#:
    <OtherMarkup>
    <MudButton .. Enabled="@IsOfVotingAge"
    <EvenMoreMarkup>

@code{
    private bool IsOfVotingAge => Age > 21
}

or you do something in the markup, like if you didn't...
Think something went wrong when following that tutorial; I would expect the page file to be called Todo.razor not Todo.cshtml

After you've played with Blazor a bit, take a look at the Blazorise and MudBlazor component libraries. I use MB mainly now, but I rate both highly; they make it quick and relatively easy to make a nice looking UI
 
Think something went wrong when following that tutorial; I would expect the page file to be called Todo.razor not Todo.cshtml

After you've played with Blazor a bit, take a look at the Blazorise and MudBlazor component libraries. I use MB mainly now, but I rate both highly; they make it quick and relatively easy to make a nice looking UI

Hello, cjard
Thanks to your correction I was able to run the tutorial project. But I wanted to practise and go a bit further, and tried to display an error message if an empty or whitespaces string was entered to the <input placeholder> and I wrote the last line in the @code { } section, which produced a compiler error "The name __builder doesn't exist in the current context".
Could you (or other member) point me on how to do this?

Last line produces error:
@page "/todo"

<PageTitle>Todo</PageTitle>

<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>
            <input type="checkbox" @bind="todo.IsDone" />
            <input @bind="todo.Title" />
        </li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;

        }
        else
        {
            <p id="error">Todo Item can't be null or white space.</p>
        }
    }
}

Thank you very much!
I'll investigate about MudBlazor. I appreciate your help and your advise.
Pablo
 
Line 34 looks completely out of place there. What happens if you delete it? Does the page compile correctly?
 
Line 34 looks completely out of place there. What happens if you delete it? Does the page compile correctly?

Hi, Skydiver:
Actually, it worked everything well thanks to cjard correction, until I added line 34, and so then a few minutes ago I was asking someone of you, how to achieve the intended stuff, that is to add a <p> to indicate that the entered string is not valid.
Thank you!
 
You don't (well, there are ways of making it possible but..) put html markup in the code area of a Blazor page. In this situation you'd probably use blazor's built in validation - see Blazor University - Validation about making the todo item description "required"..

..but in a general sense in Blazor it's all about binding; if you want to enable some button when the age is above 21, then you do something more like putting the markup in the markup area of the page and bind its enabled-ness to a boolean property which is perhaps like

C#:
    <OtherMarkup>
    <MudButton .. Enabled="@IsOfVotingAge"
    <EvenMoreMarkup>

@code{
    private bool IsOfVotingAge => Age > 21
}

or you do something in the markup, like if you didn't want to render the button at all:
C#:
    <OtherMarkup>
    @if(IsOfVotingAge){
      <MudButton ...
    }
    <EvenMoreMarkup>
@code{
  private bool IsOfVotingAge => Age > 21
}

Try and get into this mode of thinking where you put all your markup in the markup area and then use code-area properties to change the behavior of the markup rendering. Minimize the amount of code in the markup, use code to change the values of the properties and then the markup will automatically (or can be prodded to) re-render based on the new values. Compare your original code to something more like this:


C#:
<input placeholder="Something todo" @bind="newTodo" />

@if(showError){
    <p id="error">Todo Item can't be null or white space.</p>
}

<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;
    private bool showError=false;
    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
            showError=false;
        }
        else
        {
            showError=true;
        }
    }
}

You put the markup where you want it (because how would c# know where that <p you put on line 34 was supposed to appear in the markup?) and use a bool, the value of which the code can influence, to control if it's rendered out or not. Changing the value of showError in code changes the page appearance

Note I don't guarantee that the code above will work as you expect; I'm using it as a vehicle to explain how we do things in Blazor, rather than saying "this is what you intended to do" - you're doing validation, and there is a system for that, but this is the general idea of "dynamic-ness in appearance, getting code to affect what is rendered, on a Blazor page is done like this"
 
Last edited:
Solution
You don't (well, there are ways of making it possible but..) put html markup in the code area of a Blazor page. In this situation you'd probably use blazor's built in validation - see Blazor University - Validation about making the todo item description "required"..

..but in a general sense in Blazor it's all about binding; if you want to enable some button when the age is above 21, then you do something more like putting the markup in the markup area of the page and bind its enabled-ness to a boolean property which is perhaps like

C#:
    <OtherMarkup>
    <MudButton .. Enabled="@IsOfVotingAge"
    <EvenMoreMarkup>

@code{
    private bool IsOfVotingAge => Age > 21
}

or you do something in the markup, like if you didn't want to render the button at all:
C#:
    <OtherMarkup>
    @if(IsOfVotingAge){
      <MudButton ...
    }
    <EvenMoreMarkup>
@code{
  private bool IsOfVotingAge => Age > 21
}

Try and get into this mode of thinking where you put all your markup in the markup area and then use code-area properties to change the behavior of the markup rendering. Minimize the amount of code in the markup, use code to change the values of the properties and then the markup will automatically (or can be prodded to) re-render based on the new values. Compare your original code to something more like this:


C#:
<input placeholder="Something todo" @bind="newTodo" />

@if(showError){
    <p id="error">Todo Item can't be null or white space.</p>
}

<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;
    private bool showError=false;
    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
            showError=false;
        }
        else
        {
            showError=true;
        }
    }
}

You put the markup where you want it (because how would c# know where that <p you put on line 34 was supposed to appear in the markup?) and use a bool, the value of which the code can influence, to control if it's rendered out or not. Changing the value of showError in code changes the page appearance

Note I don't guarantee that the code above will work as you expect; I'm using it as a vehicle to explain how we do things in Blazor, rather than saying "this is what you intended to do" - you're doing validation, and there is a system for that, but this is the general idea of "dynamic-ness in appearance, getting code to affect what is rendered, on a Blazor page is done like this"

Hi, cjard
Excellent your help! I made a great progress in my learning for your explanation. Also I was able to write a simple calculator in another page in the project. Now it's time to go for MudBlazor and for including a DB and ADO in it. I suspect I'll come back here very soon with new questions.
Thank you (all) for being there!
Pablo
 
including a DB and ADO

Install an extension for VS called EF Core Power Tools, then use it to Reverse Engineer your existing database. Choose a context name and some folders to put things in

Right click your project name in solution explorer and choose "manage user secrets" and put a json like this:

C#:
{
  "ConnectionStrings": {
    "NameOfYourConnectionStringParameterInConfigHere": "Your;Connection;String;Goes;Here",
  },
}

Add code like this to your Program.cs:

C#:
builder.Services.AddDbContextFactory<YourContextNameHere>(optionsBuilder =>
{
    var cs = builder.Configuration.GetConnectionString("NameOfYourConnectionStringParameterInConfigHere");
    optionsBuilder.UseSqlServer(connectionString: cs)
#if DEBUG
        .EnableSensitiveDataLogging()
        .LogTo(Console.WriteLine, LogLevel.Information)
#endif
    ;
});

When accessing your DB, write queries like:


C#:
@inject IDbContextFactory<YourContextNameHere> ContextFactory { get; set; } = default!;

...

@code{

  private List<Person> People;

  async Task SomeMethodLikeOnInitializeAsync(){
    var db = await ContextFactory.CreateDbContextAsync();
    People = await db.People.Where(p => p.Name == "Smith").ToListAsync();
  }
}

It's how we do DB stuff with EF these days; low level ADO is rarely used any more
 
Well, there are some syntac error with your code, you can replace your code with below code.

C#:
@page "/todo"

<PageTitle>Todo</PageTitle>

<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>
<input placeholder="Something to do" @bind="newTodo" />
<button @onclick="AddTodo">Add Todo</button>

@code {
    private string? newTodo;

    private List<TodoItem> todos = new();

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}


I hope you will the resuly you are looking for.
Thanks
 
Back
Top Bottom