Home > Software engineering >  .NET CORE Invoke ViewComponent from Controller
.NET CORE Invoke ViewComponent from Controller

Time:12-11

I am having issues with loading a ViewComponent from a controller, my main view is Contact.cshtml and my ViewComponent is AddContact.cshtml. AddContact is a simple form with a submit button, I am trying to get it so that when the model is invalid, the component refreshes with the data that was entered and the model validation messages.

The problem is when I return "ViewComponent("AddContact", newContact)" in the controller with then invalid model 'newContact', it reloads the ViewComponent in an entirely new page and not as a partial in the Contact view. Is there some syntax I am missing or would this require something else entirely?

Contact.cshtml:

@await Component.InvokeAsync("AddContact", new { addContact = newContactModel })

AddContact.cshtml

@using (Html.BeginForm("AddContact", "Contact", FormMethod.Post))
{
    ....

    <input id="addContactBtn" type="submit" value="Add" >
}

Controller:

[HttpGet]
public ActionResult AddContact()
{
      return ViewComponent("AddContact");
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddContact(AddContact_VM newContact)
{
      if (!ModelState.IsValid)
      {
            return ViewComponent("AddContact", newContact);
      }

      OperationStatus opStat = granteeRepo.AddContact(newContact);

      return View("Contact");
 }

Component:

public class AddContact : ViewComponent
{
    public IViewComponentResult Invoke(AddContact_VM newContact)
    {
         return View("AddContact", newContact);
    }
}

CodePudding user response:

You can create a spesific action to direct requests to ViewCompoent.

Here is an example,

For your cshtml that will be directed:

<a href="#" data-url='@Url.Action("LoadParametersContent","Home",new {key="Home"})'>

For your HomeContoller.cs

   public IActionResult LoadParametersContent(string key)
   {
       return ViewComponent(key);
   }

For HomeViewComponent.cs:

    public class HomeViewComponent : ViewComponent
    {
        public IViewComponentResult Invoke()
        {
            return View("Home");
        }
    }

After that you should create your component as Home.cshtml under Shared>Components>Home.

Bonus:

I have a left-sided navbar. With anchors in that navbar I'm changing the content on the right with viewcomponents. Here is the jquery that makes that happen:

$('.nav-link').on('click', function (evt) {
    evt.preventDefault();
    evt.stopPropagation();
    var $detailDiv = $('#content-right'),
        url = $(this).data('url');

    $.get(url, function (data) {
        $detailDiv.html(data);
    });
});

CodePudding user response:

The problem is when I return "ViewComponent("AddContact", newContact)" in the controller with then invalid model 'newContact', it reloads the ViewComponent in an entirely new page and not as a partial in the Contact view.

The reason is the program first executes the content of the if statement, and then the code returns to the AddContact page.So it reloads the ViewComponent in an entirely new page and not as a partial in the Contact view.

You can try to change the return ViewComponent("AddContact", newContact); into return View("Contact"); in your if method in your controller.

I do a Demo to meet your requirement. The Demo as below.

1.In controller, use Contact action.

public class ctController : Controller
    {
        [HttpGet]
        public IActionResult Contact()
        {
            return View();
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Contact(AddContact_VM newContact)
        {

            if (!ModelState.IsValid)
            {
                return View("Contact");
            }

            OperationStatus opStat = granteeRepo.AddContact(newContact);
            return View("Contact");
        }

2.In Contact.cshtml, add @await Component.InvokeAsync("AddContact")

3.In AddContact.cshtml, change action name in form.

   @model MVCviewcompent.Models.AddContact_VM
    @using (Html.BeginForm("Contact", "ct", FormMethod.Post))
    {
        <form asp-controller="ct" asp-action="Contact" method="post">
            <table border="0" cellpadding="2" cellspacing="2">
                <tr>
                    <td>Username</td>
                    <td>
                        <input asp-for="Username" />
                    </td>
                    <td>
                        <span asp-validation-for="Username"></span>
                    </td>
                </tr>
                <tr>
                    <td>Password</td>
                    <td>
                        <input asp-for="Password" type="password" />
                    </td>
                    <td>
                        <span asp-validation-for="Password"></span>
                    </td>
                </tr>
                <tr>
                    <td>Age</td>
                    <td>
                        <input asp-for="Age" />
                    </td>
                    <td>
                        <span asp-validation-for="Age"></span>
                    </td>
                    
                </tr>
    
                <tr>
                    <td>&nbsp;</td>
                    <td>
                        <input type="submit" value="Save" />
                    </td>
                </tr>
            </table>
        </form>
}

4.In AddContact_VM .cs

public class AddContact_VM
    {
        [Required]
        [MinLength(3)]
        [MaxLength(10)]
        public string Username
        {
            get;
            set;
        }

        [Required]
        [MinLength(3)]
       
        public string Password
        {
            get;
            set;
        }


        [Required]
        [Range(18, 50)]
        public int Age
        {
            get;
            set;
        }
   }

5.The Component class is your AddContact.

Results:

enter image description here enter image description here enter image description here

  • Related