locked
Avoid page refresh after submit button execute RRS feed

  • Question

  • User2139392758 posted

    Hello all.

    I'm newbe in razor pages.

    I have a razor page with two partial pages, the first one contains data of a single record and the second one is to upload an image, each one with its own asp-page-handler OnPost for the upload File and OnPostData for the data partial.

    When I press the save data button, the upload image button no longer works, I can select the file but it does not upload it and not show in the img frame..

    Another issue is that when I save the data, the entire page is refreshed. That is, when return from the OnPost method, the entire page is refreshed. Is there a way to avoid this and that onñy refresh the partial that send the request?

    I tried to add asp-page-handler="FileUpload" in the input type button on the FileUpload partial but not work. Ii is possible to do this?

    The PageModel:

    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using System.IO;
    using System.Linq;
    using Tienda.Data;
    using Tienda.Models;
    using Microsoft.EntityFrameworkCore;
    using System.Collections.Generic;
    using System.Drawing;
    
    namespace Tienda.Pages
    {
        public class ConfigModel : PageModel
        {
            public readonly IWebHostEnvironment _environment;
            public readonly TiendaDbContext _context;
    
         #region Model
    
            [BindProperty]
            public Config Config { get; set; }
    
            [BindProperty]
            public IFormFile FileToUpload { get; set; }
    
            public List<FontFamily> FontFamList { get; } = FontFamily.Families.ToList();
    
            #endregion
    
            public ConfigModel(TiendaDbContext context, IWebHostEnvironment environment = null)
            {
                _context = context;
                _environment = environment;
            }
    
            public void OnGet()
            {
                Config = _context.Config.AsEnumerable().First();
            }
    
            public void OnPost()
            {
                if (FileToUpload != null)
                {
                    string file;
    
                    if (FileToUpload.FileName != "img_ppal.jpg")
                    {
                        file = Path.Combine(_environment.WebRootPath, "imgs", "img_ppal.jpg");
                    }
                    else
                    {
                        file = Path.Combine(_environment.WebRootPath, "imgs", FileToUpload.FileName);
                    }
    
                    using FileStream fileStream = new FileStream(file, FileMode.Create);
                    FileToUpload.CopyTo(fileStream);
                }
            }
    
            public void OnPostData()
            {
                if (ModelState.IsValid)
                {
                    _context.Entry(Config).State = EntityState.Modified;
                    _context.SaveChanges();
                }
            }
        }
    }

    The content page:

    @page
    @model Tienda.Pages.ConfigModel
    
    <form id="frm-config" method="post" class="d-flex" enctype="multipart/form-data">
    
        <div class="col-6 flex-column">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    
            <partial name="_Config" />
    
        </div>
    
        <div class="col-6 d-flex flex-column">
    
                <partial name="_FileUpload" />
    
        </div>
    
    </form>
    

    The Partial for data (for abreviate with only a couple of fields):

    @model Tienda.Pages.ConfigModel
    
    <input type="hidden" asp-for="Config.ID" />
    <input id="servidor" type="hidden" asp-for="Config.UrlServidor" />
    
    <div class="form-group">
        <strong class="m-0 p-0">Datos de la tienda</strong>
        <hr />
        <div class="form-group d-flex justify-content-between border-0 my-0 py-0">
            <div class="col-3">
                <label asp-for="Config.Marca" class="control-label"></label>
                <span asp-validation-for="Config.Marca" class="text-danger"></span>
                <input asp-for="Config.Marca" class="form-control campo" />
            </div>
    
            <div class="col-3">
                <label asp-for="Config.CIF" class="control-label"></label>
                <span asp-validation-for="Config.CIF" class="text-danger"></span>
                <input asp-for="Config.CIF" class="form-control campo" />
            </div>
        </div>
    </div>
    
    <input Id="cmd-guardar" type="submit" value="Guardar configuración" class="btn btn-dark" asp-page-handler="Data" />
    

    The Partial for Upload File:

    @model Tienda.Pages.ConfigModel
    @{
        var ImgPath = "~/imgs/img_ppal.jpg";
    }
    
    <div class="row">
        <div class="col-6 form-group d-flex flex-column align-items-end">
            <div class="form-group fg-img-ppal">
                <img class="img-fluid" src="@Url.Content(@ImgPath)" alt="@ImgPath" style="cursor:pointer" />
            </div>
    
            <input id="input-img" type="file" asp-for="FileToUpload" style="display:none" onchange="submitImg()">
            <input type="button" class="btn btn-dark" value="Subir Imagen" onclick="clicFileInput()">
        </div>
    </div>
    
    <script>
        function clicFileInput() {
            $('#input-img').click();
        }
    
        function submitImg() {
            $("#frm-config").submit();
        }
    </script>

    Thursday, July 9, 2020 8:54 PM

Answers

  • User-474980206 posted

    the only way to avoid page refresh (reload), is to use javascript and ajax.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, July 10, 2020 7:53 PM

All replies

  • User711641945 posted

    Hi FedericoLuna,

    Add this line in your OnPostData handler:

    public IActionResult OnPostData()
    {
        if (ModelState.IsValid)
        {
            _context.Entry(Config).State = EntityState.Modified;
            _context.SaveChanges();
                   
        }
        return RedirectToPage("Config");
    }

    Best Regards,

    Rena

    Friday, July 10, 2020 9:39 AM
  • User2139392758 posted

    OK. Thanks, for now it's a good solution, but this does not solve the second issue because RedirectToPage reloads the whole page producing an ugly effect by rendering the page again and this is what I want to avoid. I want to reload only the partial page that runs the Submit button.

    Thnk you again for your help.

    Friday, July 10, 2020 10:28 AM
  • User475983607 posted

    OK. Thanks, for now it's a good solution, but this does not solve the second issue because RedirectToPage reloads the whole page producing an ugly effect by rendering the page again and this is what I want to avoid. I want to reload only the partial page that runs the Submit button.

    Razor pages is a server side technology.  It is up to you to design and write a JavaScript application that handles the HTTP messages and update the current page.   This is not a new concept and the Internet is full of examples.  I recommend the following blog.  https://www.learnrazorpages.com/razor-pages/ajax

    The write up overviews different approaches.  The bottom contains links with example code.  

    Friday, July 10, 2020 11:37 AM
  • User2139392758 posted

    Yes, I have made another partial page (there really are 3) the third one uses ajax calls and it works fine. But I wanted to know if it can be done only with razor pages.

    I have use this webs to learn .Net Core and razor pages.

    (https://www.mikesdotnetting.com/, https://www.learnrazorpages.com, https://www.learnentityframeworkcore.com/)

    Thank you Mike, great work.

    Friday, July 10, 2020 3:57 PM
  • User475983607 posted

    Yes, I have made another partial page (there really are 3) the third one uses ajax calls and it works fine. But I wanted to know if it can be done only with razor pages.

    I'm a little confused.  The link in my first post has several Razor Page examples.  I'm guessing you did not read the links or the Razor Pages example is not what you're look for?  If the Razor Pages examples are not what you are looking for can you explain why?

    https://www.learnrazorpages.com/razor-pages/ajax/partial-update

    https://www.learnrazorpages.com/razor-pages/ajax/form-post

    https://www.learnrazorpages.com/web-api

    Maybe you are looking for Blazor?

    https://docs.microsoft.com/en-us/aspnet/core/blazor/?view=aspnetcore-3.1

    Friday, July 10, 2020 4:08 PM
  • User2139392758 posted

    Sorry if my English is not very good, what I say is that I use these websites frequently.

    www.learnrazorpages.com, www.mikesdotnetting.com and www.learnentityframeworkcore.com are the websites that I consult for everything related to .Net Core and Razor pages.

    I have used their examples frequently and serve me.

    I used this link https://www.learnrazorpages.com/web-api for the third partial page which is a CRUD api.

    I wanted to test if it could be done without ajax.

    I will use the other links you have given me.

    Thanks for your help.

    Friday, July 10, 2020 7:37 PM
  • User-474980206 posted

    the only way to avoid page refresh (reload), is to use javascript and ajax.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, July 10, 2020 7:53 PM
  • User475983607 posted

    I wanted to test if it could be done without ajax.

    Sure, you can use fetch in modern browsers if you do not want to use jQuery AJAX.  This concept is openly covered in the first link I provided.  

    Friday, July 10, 2020 7:54 PM
  • User-474980206 posted

    ajax is a pattern name (Asynchronous JavaScript And XML). originally you used XMLHttpRequest (or an iframe in the early days, before the request object existed).

       https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX/Getting_Started

    today while most of us request Json rather than xml, we still call it ajax. and while fetch is handy, it is just a wrapper around XMLHttpRequest and does not have all the features (process event for one).

    Friday, July 10, 2020 8:44 PM
  • User2139392758 posted

    Thank you everypne so much for your help.

    As you may have noticed, I am a novice developing web apps, although I have more than 30 years developing windows forms applications.

    I have managed to upload an image in a partial page without refreshing the whole page using ajax and api controller.

    How could I pass additional parameter to api controller?

    When I change the post method to receive parameter in the form: api/controller/param, the value of the Upload property is null.

    These are the content page and the api controller:

    @model Tienda.Pages.ConfigModel
    @{ 
        var RutaImg = "~/imgs/0.jpg";
    }
    
    <form id="frm-upload" method="post" enctype="multipart/form-data" class="col-6 form-group d-flex flex-column align-items-end">
        <div class="form-check">
            <label class="form-check-label">
                <input type="checkbox" class="form-check-input" value="" onclick="toggleMarquesina()">
                <text id="txt-chk">Activar banner</text>
            </label>
        </div>
        <br />
        <div class="form-group fg-img-ppal">
            <img id="img" class="img-fluid" src="@Url.Content(@RutaImg)" alt="@RutaImg" style="cursor:pointer" onclick="subeImagen()" />
        </div>
    
        <input id="input-img" type="file" asp-for="Upload" style="display:none" onchange="submitImg()">
        <input id="submit-img" type="button" class="btn btn-dark" value="Subir Imagen" onclick="clicFileInput()">
    </form>
    
    <script>
        function clicFileInput() {
            $('#input-img').click();
        }
    
        function submitImg() {
            let url = $("#servidor").val() + "api/subearchivo";
    
            $.ajax({
                url: url,
                data: new FormData(document.forms.namedItem("frm-upload")),
                contentType: false,
                processData: false,
                type: 'post',
                success: function (response) {
                    $("#img").attr("src", "imgs//" + response);
                }
            });
        }
    </script>
    
    using System.IO;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    
    namespace Tienda.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class SubeArchivoController : ControllerBase
        {
            public readonly IWebHostEnvironment _environment;
    
            public SubeArchivoController(IWebHostEnvironment environment)
            {
                _environment = environment;
            }
    public IFormFile Upload { get; set; } // POST api/SubeArchivo [HttpPost] public string Post() { string file = null; FileInfo finfo = null; if (Upload.FileName != "0.jpg") { file = Path.Combine(_environment.WebRootPath, "imgs", "0.jpg"); } else { file = Path.Combine(_environment.WebRootPath, "imgs", Upload.FileName); } finfo = new FileInfo(file); // Este formato de using es cuando es uns línea de código dentro del using using FileStream fileStream = new FileStream(file, FileMode.Create); Upload.CopyTo(fileStream); return finfo.Name; } } }

    That I want is send the name of the target image in a parameter instead of write it literally.

    Thank you again for your support.

    Saturday, July 11, 2020 4:11 PM
  • User-474980206 posted

    read about model binding. typically you would only pass parameters on the URL for the get method. MVC bind bind uses the form elements name s at the binding name to the model property.

    Sunday, July 12, 2020 12:54 AM