locked
How to pass data from table to model popup in razor pages RRS feed

  • Question

  • User-1032668496 posted

    Hi Everyone,

    I'm currently going through tutorials to help me learn Razor pages.

    I've created a web app that displays information from SQL in the form of a table. What I'm trying to do now is when you click on the "Details" button next to the record, for it to show the details in a bootstrap model popup.

    For this I've been following Mikes tutorial at: Razor Pages And Bootstrap - Modal Master Details (mikesdotnetting.com)

    I've managed to get the model popup to open and pass the id but i'm struggling with the part of displaying the the details of the table.

    In the tutorial it mentions about using the below code but not sure which part to put it in.

    public async Task<PartialViewResult> OnGetProductAsync(int id)
    {
        return Partial("_ProductDetails", await productService.GetProductAsync(id));
    }

    This is my code so far:

    AuthoirseDeviation.cshtml

    @page
    @model Cv2.AuthoriseDeviationModel
    @{
        ViewData["Title"] = "Authorise Deviation";
    }
    
    <h1>Authorise Deviation</h1>
    
    <div class="row">
        <div class="col-12">
            <!-- Default box -->
            <div class="card">
                <div class="card-header bg-warning">
                    <h3 class="card-title ">Issues & Deviations</h3>
    
                </div>
                <div class="card-body">
                    <div class="row">
                        <div class="col-12">
                            <div class="row">
                                <table class="table table-sm">
                                    <thead>
                                        <tr>
                                            <th>Module</th>
                                            <th>Process</th>
                                            <th>Reason</th>
                                            <th>Workstation</th>
                                            <th>Requester</th>
                                            <th>Details</th>
    
    
                                        </tr>
                                    </thead>
                                    <tbody>
    
                                        @foreach (var CurrentDeviationRequests in Model.CurrentDeviationRequests)
                                        {
                                            <tr>
                                                <td>@CurrentDeviationRequests.ModuleIdent</td>
                                                <td>@CurrentDeviationRequests.QuestionTitle</td>
                                                <td>@CurrentDeviationRequests.DeviationDesc </td>
                                                <td>@CurrentDeviationRequests.WorkStationTitle</td>
                                                <td>@CurrentDeviationRequests.Username</td>
                                                <td><button class="btn btn-sm btn-dark details" data-id="@CurrentDeviationRequests.DeviationLogID" data-toggle="modal" data-target="#modal-logDeviation">Details</button></td>
                                            </tr>
                                        }
    
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                </div>
                <!-- /.card-body -->
            </div>
            <!-- /.card -->
        </div>
    </div>
    
    <div class="modal fade" id="modal-logDeviation">
        <div class="modal-dialog modal-xl">
            <div class="modal-content bg-default">
                <div class="modal-header">
                    <h4 class="modal-title">Authorise Deviation</h4>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                </div>
            </div>
            <div class="modal-footer justify-content-between">
            </div>
        </div>
        <!-- /.modal-content -->
    </div>
    
    @section scripts{
        <script>
            $(function () {
                $('button.details').on('click', function () {
                    $('.modal-body').load(`/AuthoriseDeviation/product?id=${$(this).data('id')}`);
                    alert($(this).data('id'));
                });
            })
        </script>
    }
    

    AuthoriseDeviation.cshtml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Cv2.Models;
    using Cv2.Services;
    using Microsoft.AspNetCore.Http;
    
    namespace Cv2
    {
        public class AuthoriseDeviationModel : PageModel
        {
    
            private readonly IGet_WorkstationDeviationRequests get_WorkstationDeviationRequests;
    
            public IEnumerable<DeviationRequests> CurrentDeviationRequests { get; set; }
    
            public void OnGet()
            {
                CurrentDeviationRequests = get_WorkstationDeviationRequests.GetDeviationRequests("A13B", "5317DBA3");
            }
    
            public AuthoriseDeviationModel(IGet_WorkstationDeviationRequests get_WorkstationDeviationRequests)
            {
                this.get_WorkstationDeviationRequests = get_WorkstationDeviationRequests;
            }
    
            public void OnPostCompleteProcess(int WSQuestionID)
            {
                CurrentDeviationRequests = get_WorkstationDeviationRequests.GetDeviationRequests("A13B", "5317DBA3");
            }
    
        }
    }
    

    _DeviationDetails.cshtml Partial View

    @page
    @model Cv2.Models.DeviationRequests  
    
    <div>
        <span class="d-inline-block">Description:</span><span>@Model.DeviationDesc</span>
    </div>

    Many thanks for your help on this.

    Thursday, February 11, 2021 1:07 PM

Answers

  • User475983607 posted

    codingitup

    In the tutorial it mentions about using the below code but not sure which part to put it in.

    public async Task<PartialViewResult> OnGetProductAsync(int id)
    {
        return Partial("_ProductDetails", await productService.GetProductAsync(id));
    }

    The code snippet goes in your master page.  The master page is responsible for returning the partial content that populates the Bootstrap modal.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 11, 2021 1:19 PM
  • User475983607 posted

    You forgot to include the service declaration and dependency injection in the master page.  Plus you are not returning the partial.  You are not following the blog which returns partial HTML used to populate the modal.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 11, 2021 1:54 PM
  • User-821857111 posted

    _DeviationDetails.cshtml Partial View

    @page
    @model Cv2.Models.DeviationRequests  
    
    <div>
        <span class="d-inline-block">Description:</span><span>@Model.DeviationDesc</span>
    </div>

    Many thanks

    If that's a partial, it should not have @page at the top.

     public async Task<PartialViewResult> OnGetDeviationDetailAsync(int id)
            {
                return Partial("_DeviationDetails", await APIGet_WorkstationDeviationRequests.GetDeviationDetailsAsync(id));
            }

    That should be 

    return Partial("_DeviationDetails", await get_WorkstationDeviationRequests.GetDeviationDetailsAsync(id));

    And then in your view:

    @section scripts{
        <script>
            $(function () {
                $('button.details').on('click', function () {
                    $('.modal-body').load(`/AuthoriseDeviation?handler=DeviationDetail&id=${$(this).data('id')}`);
                    alert($(this).data('id'));
                });
            })
        </script>
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 11, 2021 2:10 PM

All replies

  • User475983607 posted

    codingitup

    In the tutorial it mentions about using the below code but not sure which part to put it in.

    public async Task<PartialViewResult> OnGetProductAsync(int id)
    {
        return Partial("_ProductDetails", await productService.GetProductAsync(id));
    }

    The code snippet goes in your master page.  The master page is responsible for returning the partial content that populates the Bootstrap modal.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 11, 2021 1:19 PM
  • User-1032668496 posted

    Hi Mgebhard,

    That's great thank you. So I I've added that in but It underlines with An object reference is required for the non static field, method, or property APiGet_WorkstationDeviationRequests.GetDeviationDetailAsyc.

    This is my main page now AuthoriseDeviation.cshml.cs:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Cv2.Models;
    using Cv2.Services;
    using Microsoft.AspNetCore.Http;
    
    namespace Cv2
    {
        public class AuthoriseDeviationModel : PageModel
        {
    
            private readonly IGet_WorkstationDeviationRequests get_WorkstationDeviationRequests;
    
            public IEnumerable<DeviationRequests> CurrentDeviationRequests { get; set; }
    
            public void OnGet()
            {
                CurrentDeviationRequests = get_WorkstationDeviationRequests.GetDeviationRequests("A13B", "5317DBA3");
            }
    
            public AuthoriseDeviationModel(IGet_WorkstationDeviationRequests get_WorkstationDeviationRequests)
            {
                this.get_WorkstationDeviationRequests = get_WorkstationDeviationRequests;
            }
    
            public void OnPostCompleteProcess(int WSQuestionID)
            {
                CurrentDeviationRequests = get_WorkstationDeviationRequests.GetDeviationRequests("A13B", "5317DBA3");
            }
    
            public async Task<PartialViewResult> OnGetDeviationDetailAsync(int id)
            {
                return Partial("_DeviationDetails", await APIGet_WorkstationDeviationRequests.GetDeviationDetailsAsync(id));
            }
    
        }
    }
    

    And the SQL connection class APIGet_WorkStationDeviationRequests.cs

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Cv2.Models;
    using Microsoft.Data.SqlClient;
    using Microsoft.EntityFrameworkCore;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Cv2.Services
    {
        public class APIGet_WorkstationDeviationRequests : IGet_WorkstationDeviationRequests
        {
    
            private readonly AppDbContext context;
            public async Task<DeviationRequests> GetDeviationDetailsAsync(int id) => await context.apiDeviationRequests.Include(p => p.DeviationDesc).FirstOrDefaultAsync(p => p.DeviationLogID == id);
    
            public APIGet_WorkstationDeviationRequests(AppDbContext context)
            {
                this.context = context;
            }
    
            public IEnumerable<DeviationRequests> GetDeviationRequests(string ModuleIdent, string SUB_ID)
            {
                var parameters = new List<SqlParameter>();
                parameters.Add(new SqlParameter("@SUB_ID", SUB_ID));
                return context.apiDeviationRequests.FromSqlRaw<DeviationRequests>("dbo.Get_WorkstationDeviationRequests @SUB_ID", parameters: parameters.ToArray())
                   .ToList();
            }
    
        }
    
        
    }
    
    

    Many thanks for your help.

    Thursday, February 11, 2021 1:47 PM
  • User475983607 posted

    You forgot to include the service declaration and dependency injection in the master page.  Plus you are not returning the partial.  You are not following the blog which returns partial HTML used to populate the modal.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 11, 2021 1:54 PM
  • User-821857111 posted

    _DeviationDetails.cshtml Partial View

    @page
    @model Cv2.Models.DeviationRequests  
    
    <div>
        <span class="d-inline-block">Description:</span><span>@Model.DeviationDesc</span>
    </div>

    Many thanks

    If that's a partial, it should not have @page at the top.

     public async Task<PartialViewResult> OnGetDeviationDetailAsync(int id)
            {
                return Partial("_DeviationDetails", await APIGet_WorkstationDeviationRequests.GetDeviationDetailsAsync(id));
            }

    That should be 

    return Partial("_DeviationDetails", await get_WorkstationDeviationRequests.GetDeviationDetailsAsync(id));

    And then in your view:

    @section scripts{
        <script>
            $(function () {
                $('button.details').on('click', function () {
                    $('.modal-body').load(`/AuthoriseDeviation?handler=DeviationDetail&id=${$(this).data('id')}`);
                    alert($(this).data('id'));
                });
            })
        </script>
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 11, 2021 2:10 PM
  • User-1032668496 posted

    Hi Mike,

    I though I recognized the handle to your blog :-) and thanks for your help.

    So my main page now looks like this:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Cv2.Models;
    using Cv2.Services;
    using Microsoft.AspNetCore.Http;
    
    namespace Cv2
    {
        public class AuthoriseDeviationModel : PageModel
        {
    
            private readonly IGet_WorkstationDeviationRequests get_WorkstationDeviationRequests;
            
            public IEnumerable<DeviationRequests> CurrentDeviationRequests { get; set; }
    
            public void OnGet()
            {
                CurrentDeviationRequests = get_WorkstationDeviationRequests.GetDeviationRequests("A13B", "5317DBA3");
            }
    
            public AuthoriseDeviationModel(IGet_WorkstationDeviationRequests get_WorkstationDeviationRequests)
            {
                this.get_WorkstationDeviationRequests = get_WorkstationDeviationRequests;
            }
    
            public void OnPostCompleteProcess(int WSQuestionID)
            {
                CurrentDeviationRequests = get_WorkstationDeviationRequests.GetDeviationRequests("A13B.1.18", "5317DBA3");
            }
    
            public async Task<PartialViewResult> OnGetDeviationDetailAsync(int id)
            {
                return Partial("_DeviationDetails", await get_WorkstationDeviationRequests.GetDeviationDetailsAsync(id));
            }
    
        }
    }
    

    It underlines GetDeviationDetailsAsync on the line:

    return Partial("_DeviationDetails", await get_WorkstationDeviationRequests.GetDeviationDetailsAsync(id));

    With the message: IGet_WorkstationDeviationRequests does not contain a definition for GetDeviationDetailsAsync and no accessible extension method GetDeviationDetailsAsync accepting a first argument of type IGet_WorkstationDeviationRequests could not be found.

    This is my IGet_WorkstationDeviationRequests.cs

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Cv2.Models;
    
    namespace Cv2.Services
    {
        public interface IGet_WorkstationDeviationRequests
        {        IEnumerable<DeviationRequests> GetDeviationRequests(string ModuleIdent, string SUB_ID);
        }
    }
    
    

    I'm guessing I need to write some code to retrieve this data now based on the ID?

    Thursday, February 11, 2021 2:39 PM
  • User475983607 posted

    codingitup

    I'm guessing I need to write some code to retrieve this data now based on the ID?

    You are still missing the constructor injection bits.  The GetDeviationDetailsAsync(id) does not match the interface signature.

    public interface IGet_WorkstationDeviationRequests
    {        
        IEnumerable<DeviationRequests> GetDeviationRequests(string ModuleIdent, string SUB_ID);
    }

    Thursday, February 11, 2021 3:23 PM
  • User-1032668496 posted

    Ah, that bit gets the initial data.

    I've added this, not sure if it's correct:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Cv2.Models;
    using System.Threading.Tasks;
    
    namespace Cv2.Services
    {
        public interface IGet_WorkstationDeviationRequests
        {        IEnumerable<DeviationRequests> GetDeviationRequests(string ModuleIdent, string SUB_ID);
            public Task<DeviationRequests> GetDeviationDetailsAsync(int id);
        }
    }
    

    The error has gone but I put a break point on this in AuthoiriseDeviation:

            public async Task<PartialViewResult> OnGetDeviationDetail(int id)
            {
                return Partial("_DeviationDetails", await get_WorkstationDeviationRequests.GetDeviationDetailsAsync(id));
            }

    I was thinking this would break when I press one of the detail buttons but it doesn't. 

    Thursday, February 11, 2021 3:32 PM
  • User475983607 posted

    Basic example.

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace RazorSqlite.Pages
    {
        public class IndexModel : PageModel
        {
            private readonly ILogger<IndexModel> _logger;
    
            public IndexModel(ILogger<IndexModel> logger)
            {
                _logger = logger;
            }
    
            public void OnGet()
            {
    
            }
    
            public PartialViewResult OnGetRolesListPartialAsync()
            {
                return Partial("_myPartial");
            }
        }
    }
    
    @page "{handler?}"
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <h1>Index</h1>
    
    <div>
        <input id="Button1" type="button" value="button" />
    </div>
    <div id="myPartial">
    
    </div>
    
    @section scripts{
        <script>
            $('#Button1').click(function () {
                $('#myPartial').load('/index/RolesListPartial');
            });        
        </script>
    }

    Partial

    @model RazorSqlite.Pages.Shared._myPartialModel
    @{
    }
    
    <h1>Hello World</h1>

    Thursday, February 11, 2021 4:00 PM
  • User-821857111 posted

    Did you change the JavaScript to include the handler name in the query string? If so, open the browser developer tools (F12) before you click the button and see what happens in the Network tab.

    Thursday, February 11, 2021 4:12 PM
  • User-1032668496 posted

    HI Mike,

    Yes, I changed it to:

    @section scripts{
        <script>
            $(function () {
                $('button.details').on('click', function () {
                    $('.modal-body').load(`/AuthoriseDeviation?handler=DeviationDetail&id=${$(this).data('id')}`);
                });
            })
        </script>
    }

    Ah with using F12 and looking at the network it ran into a 404 error. The URL produced was: https://localhost:44396/AuthoriseDeviation?handler=DeviationDetail&id=15

    Ah that's because the handler is contained within a folder called quality so I've change it to:

    @section scripts{ <script> $(function () { $('button.details').on('click', function () { $('.modal-body').load(`/Quality/AuthoriseDeviation?handler=DeviationDetail&id=${$(this).data('id')}`); }); }) </script> }

    It now breaks so I'll see what's happening now and come back to you. Thanks for the guidance. 

    Thursday, February 11, 2021 4:17 PM
  • User-1032668496 posted

    So I've just looked at the F12 and Network tab and it now comes up with a 500 error. It looks like it's on this line:

    public async Task<DeviationRequests> GetDeviationDetailsAsync(int id) => await context.apiDeviationRequests.FirstOrDefaultAsync(p => p.DeviationLogID == id);

    This is within my data layer called APIGet_WorkstationRequests.cs:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Cv2.Models;
    using Microsoft.Data.SqlClient;
    using Microsoft.EntityFrameworkCore;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Cv2.Services
    {
        public class APIGet_WorkstationDeviationRequests : IGet_WorkstationDeviationRequests
        {
    
            private readonly AppDbContext context;
            public async Task<DeviationRequests> GetDeviationDetailsAsync(int id) => await context.apiDeviationRequests.FirstOrDefaultAsync(p => p.DeviationLogID == id);
    
            public APIGet_WorkstationDeviationRequests(AppDbContext context)
            {
                this.context = context;
            }
    
            public IEnumerable<DeviationRequests> GetDeviationRequests(string ModuleIdent, string SUB_ID)
            {
                var parameters = new List<SqlParameter>();
                parameters.Add(new SqlParameter("@SUB_ID", SUB_ID));
                return context.apiDeviationRequests.FromSqlRaw<DeviationRequests>("dbo.Get_WorkstationDeviationRequests @SUB_ID", parameters: parameters.ToArray())
                   .ToList();
            }
    
        }
     
    }
    
    

    If I enter the url into a browser I get:

    SqlException: Invalid object name 'apiDeviationRequests'.

    This is my AppDBContext too:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.EntityFrameworkCore;
    using Cv2.Models;
    
    namespace Cv2.Services
    {
        public class AppDbContext : DbContext
        {
            public AppDbContext(DbContextOptions<AppDbContext> options)
                : base(options)
            {
            }
    
            public DbSet<ModuleDetails> ModuleDetails { get; set; }
            public DbSet<DeviationRequests> apiDeviationRequests { get; set; }
        }
    }
    
    

    Thursday, February 11, 2021 5:21 PM
  • User-821857111 posted

    codingitup

    SqlException: Invalid object name 'apiDeviationRequests'.

    The SQL expects a table or other object called apiDeviationRequests. Doesn't look like you have one with that name in the DB?

    Thursday, February 11, 2021 6:15 PM