Posta ett formulär i ASP.NET Core

Den här artikeln handlar om formulär i ASP.NET Core, hur man validerar dem och hur man skickar in datan. Syftet med ett formulär är att samla in data, validera denna data och spara datan i en databas.

För att skapa och sända ett formulär i ASP.NET Core behöver du en vy, en controller och en modell. Du kan skicka formuläret direkt till controllern eller använda ajax/javascript för att skicka formuläret till en controller. Formvalidering görs vanligtvis genom en kombination av javascript och metoder i en controller.

Kodning av formulärdata

Formulärdata kan kodas på 3 olika sätt, den typ som används är specificerad i attributet enctype i formtaggen.

application/x-www-form-urlencoded: Data skickas som nyckelvärdespar och alla data är kodade.

multipart/form-data: Data skickas som sektioner och ingen data kodas. Denna typ måste användas om du har en filuppladdningskontroll i ditt formulär.

text/plain: Data skickas som den är, ingen kodning. Kan användas för att skicka ett JSON-dokument eller ett XML-dokument.

Bibliotek

Vi behöver några jquery/javascript-bibliotek för vårt formulär. Dessa bibliotek importeras i vår layoutvy, det är smidigt att importera alla bibliotek på ett ställe. Jquery används för att posta formuläret med ajax och används vid validering. Toastr används för att skicka små meddelanden till användaren och Font Awesome används för att få snygga ikoner.
Jquery validation och Jquery validate unobtrusive används för att validera formuläret.

<environment names="Development">
    <link href="@this.tools.GetFilePath("/css/toastr.css")" rel="stylesheet" />
    <script src="/js/jquery/v3.3.1/jquery.js"></script>
    <script src="/js/jquery-validation/v1.17.0/jquery.validate.js"></script>
    <script src="/js/jquery-validation-unobtrusive/v3.2.8/jquery.validate.unobtrusive.js"></script>
    <script src="/js/toastr/v2.1.4/toastr.js"></script>
    <script src="/js/js-cookie/v2.2.0/js.cookie.js"></script>
    <script src="/js/font-awesome/v5.3.1/all.js"></script>
</environment>
<environment names="Staging,Production">
    <link href="@this.tools.GetFilePath("/css/toastr.min.css")" rel="stylesheet" />
    <script src="/js/jquery/v3.3.1/jquery.min.js"></script>
    <script src="/js/jquery-validation/v1.17.0/jquery.validate.min.js"></script>
    <script src="/js/jquery-validation-unobtrusive/v3.2.8/jquery.validate.unobtrusive.min.js"></script>
    <script src="/js/toastr/v2.1.4/toastr.min.js"></script>
    <script src="/js/js-cookie/v2.2.0/js.cookie.min.js"></script>
    <script src="/js/font-awesome/v5.3.1/all.min.js"></script>
</environment>

Modeller

Huvudmodellerna för vårt formulär är ResponseData, StaticPageDocument och StaticPageDetail. ResponseData används för att skicka meddelanden till användaren och de andra två modellerna är viktiga för att visa och spara data i formuläret.

public class ResponseData
{
    #region variables

    public bool success { get; set; }
    public string id { get; set; }
    public string message { get; set; }
    public string url { get; set; }

    #endregion

    #region Constructors

    public ResponseData()
    {
        // Set values for instance variables
        this.success = false;
        this.id = "";
        this.message = "";
        this.url = "";

    } // End of the constructor

    public ResponseData(bool success, string id, string message)
    {
        // Set values for instance variables
        this.success = success;
        this.id = id;
        this.message = message;
        this.url = "";

    } // End of the constructor

    public ResponseData(bool success, string id, string message, string url)
    {
        // Set values for instance variables
        this.success = success;
        this.id = id;
        this.message = message;
        this.url = url;

    } // End of the constructor

    #endregion

} // End of the class
public class StaticPageDocument
{
    #region Variables

    public string id { get; set; }
    public string model_type { get; set; }
    public Int32 connection_id { get; set; }
    public string meta_robots { get; set; }
    public Int32 show_as_page { get; set; }
    public string page_name { get; set; }
    public DateTime date_updated { get; set; }
    public string main_image { get; set; }
    public IList<string> images { get; set; }
    public IList<string> keywords { get; set; }
    public IDictionary<string, StaticPageDetail> translations { get; set; }

    #endregion

    #region Constructors

    public StaticPageDocument()
    {
        // Set values for instance variables
        this.id = Guid.NewGuid().ToString();
        this.model_type = "static_page";
        this.connection_id = 0;
        this.meta_robots = "";
        this.show_as_page = 0;
        this.page_name = "";
        this.date_updated = DateTime.UtcNow;
        this.main_image = "";
        this.images = new List<string>();
        this.keywords = new List<string>();
        this.translations = new Dictionary<string, StaticPageDetail>();

    } // End of the constructor

    #endregion

    #region Get methods

    public StaticPageDetail GetTranslation(string key)
    {
        // Create the string to return
        StaticPageDetail translation = new StaticPageDetail();

        // Check if the dictionary contains the key
        if (this.translations.ContainsKey(key))
        {
            translation = this.translations[key];
        }

        // Return the value
        return translation;

    } // End of the GetTranslation method

    #endregion

} // End of the class
public class StaticPageDetail
{
    #region Variables

    public string link_name { get; set; }
    public string title { get; set; }
    public string text_html { get; set; }
    public string meta_description { get; set; }
    public string meta_keywords { get; set; }
        
    #endregion

    #region Constructors

    public StaticPageDetail()
    {
        // Set values for instance variables
        this.link_name = "";
        this.title = "";
        this.text_html = "";
        this.meta_description = "";
        this.meta_keywords = "";

    } // End of the constructor

    #endregion

} // End of the class

Controller

Denna controller innehåller metoder som vi behöver för att administrera statiska sidor, denna klass utgör länken mellan vyer och arkivklasser. Denna controller ska returnera vyer och hantera postningar av formulär.

public class admin_static_pagesController : BaseController
{
    #region Variables

    private readonly IStaticPageRepository static_page_repository;
    private readonly ILanguageRepository language_repository;
    private readonly IWebDomainRepository web_domain_repository;
    private readonly IStaticTextRepository static_text_repository;
    private readonly IAdministratorRepository administrator_repository;
    private readonly IBlobStorageRepository blob_storage_repository;

    #endregion

    #region Constructors

    public admin_static_pagesController(IRazorViewEngine view_engine, IStaticPageRepository static_page_repository, ILanguageRepository language_repository, 
        IWebDomainRepository web_domain_repository,  IStaticTextRepository static_text_repository, IAdministratorRepository administrator_repository,
        IBlobStorageRepository blob_storage_repository) : base(view_engine)
    {
        // Set values for instance variables
        this.static_page_repository = static_page_repository;
        this.language_repository = language_repository;
        this.web_domain_repository = web_domain_repository;
        this.static_text_repository = static_text_repository;
        this.administrator_repository = administrator_repository;
        this.blob_storage_repository = blob_storage_repository;

    } // End of the constructor

    #endregion

    #region View methods

    [HttpGet]
    [Authorize(Roles = "Administrator,Editor,Translator")]
    public async Task<IActionResult> index()
    {
        // Get the current domain
        WebDomain current_domain = await this.web_domain_repository.GetCurrentDomain(ControllerContext.HttpContext);

        // Get translated texts
        KeyStringList tt = await this.static_text_repository.GetFromCache(current_domain.back_end_language_code);

        // Get keywords
        string kw = "";
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("kw") == true)
        {
            kw = ControllerContext.HttpContext.Request.Query["kw"];
        }

        // Get the sort field
        string sf = "";
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("sf") == true)
        {
            sf = ControllerContext.HttpContext.Request.Query["sf"];
        }

        // Get the sort order
        string so = "";
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("so") == true)
        {
            so = ControllerContext.HttpContext.Request.Query["so"];
        }

        // Get the page size
        Int32 pz = 10;
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("pz") == true)
        {
            Int32.TryParse(ControllerContext.HttpContext.Request.Query["pz"], out pz);
        }

        // Add data to the view
        ViewBag.CurrentDomain = current_domain;
        ViewBag.TranslatedTexts = tt;
        ViewBag.AuthorizationLevel = this.administrator_repository.GetAuthorizationLevel(ControllerContext.HttpContext.User);
        ViewBag.Keywords = kw;
        ViewBag.SortField = sf;
        ViewBag.SortOrder = so;
        ViewBag.PageSize = pz;

        // Return the view
        return View();

    } // End of the index method

    [HttpGet]
    [Authorize(Roles = "Administrator,Editor")]
    public async Task<IActionResult> edit(string id = "")
    {
        // Get the current domain
        WebDomain current_domain = await this.web_domain_repository.GetCurrentDomain(ControllerContext.HttpContext);

        // Get translated texts
        KeyStringList tt = await this.static_text_repository.GetFromCache(current_domain.back_end_language_code);

        // Get keywords
        string kw = "";
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("kw") == true)
        {
            kw = ControllerContext.HttpContext.Request.Query["kw"];
        }

        // Get the sort field
        string sf = "";
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("sf") == true)
        {
            sf = ControllerContext.HttpContext.Request.Query["sf"];
        }

        // Get the sort order
        string so = "";
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("so") == true)
        {
            so = ControllerContext.HttpContext.Request.Query["so"];
        }

        // Get the page size
        Int32 pz = 10;
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("pz") == true)
        {
            Int32.TryParse(ControllerContext.HttpContext.Request.Query["pz"], out pz);
        }

        // Get items
        ModelItem<StaticPageDocument> static_page_model = await this.static_page_repository.GetById(id);

        // Add data to the view
        ViewBag.CurrentDomain = current_domain;
        ViewBag.TranslatedTexts = tt;
        ViewBag.AuthorizationLevel = this.administrator_repository.GetAuthorizationLevel(ControllerContext.HttpContext.User);
        ViewBag.Post = static_page_model.item != null ? static_page_model.item : new StaticPageDocument();
        ViewBag.Keywords = kw;
        ViewBag.SortField = sf;
        ViewBag.SortOrder = so;
        ViewBag.PageSize = pz;

        // Return the edit view
        return View("edit");

    } // End of the edit method

    [HttpGet]
    [Authorize(Roles = "Administrator,Editor,Translator")]
    public async Task<IActionResult> translate(string id = "", string lang = "")
    {
        // Get the current domain
        WebDomain current_domain = await this.web_domain_repository.GetCurrentDomain(ControllerContext.HttpContext);

        // Get translated texts
        KeyStringList tt = await this.static_text_repository.GetFromCache(current_domain.back_end_language_code);

        // Get keywords
        string kw = "";
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("kw") == true)
        {
            kw = ControllerContext.HttpContext.Request.Query["kw"];
        }

        // Get the sort field
        string sf = "";
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("sf") == true)
        {
            sf = ControllerContext.HttpContext.Request.Query["sf"];
        }

        // Get the sort order
        string so = "";
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("so") == true)
        {
            so = ControllerContext.HttpContext.Request.Query["so"];
        }

        // Get the page size
        Int32 pz = 10;
        if (ControllerContext.HttpContext.Request.Query.ContainsKey("pz") == true)
        {
            Int32.TryParse(ControllerContext.HttpContext.Request.Query["pz"], out pz);
        }

        // Get items
        ModelItem<LanguagesDocument> languages_model = await this.language_repository.GetByType();
        ModelItem<StaticPageDocument> static_page_model = await this.static_page_repository.GetById(id);

        // Add data to the view
        ViewBag.CurrentDomain = current_domain;
        ViewBag.TranslatedTexts = tt;
        ViewBag.AuthorizationLevel = this.administrator_repository.GetAuthorizationLevel(ControllerContext.HttpContext.User);
        ViewBag.Post = static_page_model.item;
        ViewBag.LanguageCode = lang;
        ViewBag.Languages = languages_model.item;
        ViewBag.Keywords = kw;
        ViewBag.SortField = sf;
        ViewBag.SortOrder = so;
        ViewBag.PageSize = pz;

        // Redirect the user if the post is null
        if (ViewBag.Post == null)
        {
            // Redirect the user to the list
            return Redirect("/admin_static_pages");
        }

        // Return the view
        return View();

    } // End of the translate method

    #endregion

    #region Post methods

    [HttpPost]
    public IActionResult search(IFormCollection collection)
    {
        // Get the search data
        string keywordString = collection["txtSearch"];
        string sort_field = collection["selectSortField"];
        string sort_order = collection["selectSortOrder"];
        string page_size = collection["selectPageSize"];

        // Return the url with search parameters
        return Redirect("/admin_static_pages?kw=" + WebUtility.UrlEncode(keywordString) + "&sf=" + sort_field + "&so=" + sort_order + "&pz=" + page_size);

    } // End of the search method

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "Administrator,Editor")]
    public async Task<IActionResult> edit(IFormCollection collection)
    {
        // Get the current domain
        WebDomain current_domain = await this.web_domain_repository.GetCurrentDomain(ControllerContext.HttpContext);

        // Get translated texts
        KeyStringList tt = await this.static_text_repository.GetFromCache(current_domain.back_end_language_code);

        // Get the id
        string id = collection["txtId"].ToString();

        // Get the static page document
        ModelItem<StaticPageDocument> static_page_model = await this.static_page_repository.GetById(id);
        StaticPageDocument post = static_page_model.item;

        // Make sure that the post not is null
        if (post == null)
        {
            post = new StaticPageDocument();
            post.id = id;
        }

        // Update values
        post.connection_id = DataValidation.ParseInt32(collection["selectConnection"].ToString(), 0);
        post.meta_robots = collection["selectMetaRobots"].ToString();
        post.show_as_page = DataValidation.ParseInt32(collection["cbShowAsPage"], 0);
        post.date_updated = DateTime.UtcNow;
        post.page_name = collection["txtPageName"].ToString();
        post.main_image = collection["txtMainImage"].ToString();
        post.keywords = collection["txtKeywords"].ToString().Split(',', StringSplitOptions.RemoveEmptyEntries);

        // Make sure that keywords is lowercase and trimmed
        for (int i = 0; i < post.keywords.Count; i++)
        {
            post.keywords[i] = post.keywords[i].ToLower().Trim();
        }

        if (post.translations.ContainsKey(current_domain.back_end_language_code) == true)
        {
            // Get the detail post
            StaticPageDetail dp = post.translations[current_domain.back_end_language_code];
            dp.link_name = collection["txtLinkName"].ToString();
            dp.meta_description = collection["txtMetaDescription"].ToString();
            dp.meta_keywords = collection["txtMetaKeywords"].ToString();
            dp.text_html = collection["txtTextHtml"].ToString();
            dp.title = collection["txtTitle"].ToString();
        }
        else
        {
            // Create a new detail post
            StaticPageDetail dp = new StaticPageDetail();
            dp.link_name = collection["txtLinkName"].ToString();
            dp.meta_description = collection["txtMetaDescription"].ToString();
            dp.meta_keywords = collection["txtMetaKeywords"].ToString();
            dp.text_html = collection["txtTextHtml"].ToString();
            dp.title = collection["txtTitle"].ToString();

            // Add the detail post
            post.translations.Add(current_domain.back_end_language_code, dp);
        }

        // Verify the page name
        ResponseData data = await verify_page_name(tt, post.id, post.page_name);

        // Return an error response
        if (data.success == false)
        {
            return Json(data: data);
        }

        // Add or update the post
        await this.static_page_repository.Upsert(post);

        // Return a success response
        return Json(data: new ResponseData(true, "", String.Format(tt.Get("success_post_updated"), tt.Get("static_page") + " (" + post.id + ")")));

    } // End of the edit method

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "Administrator,Editor,Translator")]
    public async Task<IActionResult> translate(IFormCollection collection)
    {
        // Get the current domain
        WebDomain current_domain = await this.web_domain_repository.GetCurrentDomain(ControllerContext.HttpContext);

        // Get translated texts
        KeyStringList tt = await this.static_text_repository.GetFromCache(current_domain.back_end_language_code);

        // Get the id
        string id = collection["txtId"].ToString();
        string language_code = collection["selectLanguage"].ToString();

        // Get the static page document
        ModelItem<StaticPageDocument> static_page_model = await this.static_page_repository.GetById(id);
        StaticPageDocument post = static_page_model.item;

        // Make sure that the post not is null
        if (post == null)
        {
            // Return an error response
            return Json(data: new ResponseData(false, "", String.Format(tt.Get("error-field-invalid"), tt.Get("id") + ": " + post.id)));
        }

        // Update values
        if (post.translations.ContainsKey(language_code) == true)
        {
            // Update the detail post
            StaticPageDetail dp = post.translations[language_code];
            dp.link_name = collection["txtTranslatedLinkName"].ToString();
            dp.meta_description = collection["txtTranslatedMetaDescription"].ToString();
            dp.meta_keywords = collection["txtTranslatedMetaKeywords"].ToString();
            dp.text_html = collection["txtTranslatedTextHtml"].ToString();
            dp.title = collection["txtTranslatedTitle"].ToString();
        }
        else
        {
            // Create a new detail post
            StaticPageDetail dp = new StaticPageDetail();
            dp.link_name = collection["txtTranslatedLinkName"].ToString();
            dp.meta_description = collection["txtTranslatedMetaDescription"].ToString();
            dp.meta_keywords = collection["txtTranslatedMetaKeywords"].ToString();
            dp.text_html = collection["txtTranslatedTextHtml"].ToString();
            dp.title = collection["txtTranslatedTitle"].ToString();

            // Add the detail post
            post.translations.Add(language_code, dp);
        }

        // Update the post
        await this.static_page_repository.Update(post);

        // Return a success response
        return Json(data: new ResponseData(true, "", String.Format(tt.Get("success_post_updated"), tt.Get("static_page") + " (" + post.id + ")")));

    } // End of the translate method

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "Administrator,Editor,Translator")]
    public async Task<IActionResult> images(IFormCollection collection)
    {
        // Get the current domain
        WebDomain current_domain = await this.web_domain_repository.GetCurrentDomain(ControllerContext.HttpContext);

        // Get translated texts
        KeyStringList tt = await this.static_text_repository.GetFromCache(current_domain.back_end_language_code);

        // Get the id
        string id = collection["txtId"].ToString();

        // Get the static page document
        ModelItem<StaticPageDocument> static_page_model = await this.static_page_repository.GetById(id);
        StaticPageDocument post = static_page_model.item;

        // Make sure that the post not is null
        if (post == null)
        {
            // Return an error response
            return Json(data: new ResponseData(false, "", String.Format(tt.Get("error_no_post_found"), id)));
        }

        // Check for images to delete
        IList<string> images = collection["txtImageSrc"].ToArray();
        foreach(string src in post.images)
        {
            if(images.Contains(src) == false)
            {
                // Delete the image
                await this.blob_storage_repository.Delete("media", src);
            }
        }

        // Set images
        post.images = new List<string>();
        foreach (string img in images)
        {
            post.images.Add(img);
        }

        // Get files
        IFormFileCollection files = collection.Files;
        for (int i = 0; i < files.Count; i++)
        {
            // Just continue if the file is empty
            if (files[i].Length == 0)
                continue;

            // Get the filename
            string filename = Guid.NewGuid().ToString() + Path.GetExtension(files[i].FileName);

            // Add the blob
            await this.blob_storage_repository.UploadFromStream("media", filename, files[i].OpenReadStream());

            // Add the image src to the list
            post.images.Add(filename);
        }

        // Add or update the post
        await this.static_page_repository.Upsert(post);

        // Return a success response
        return Json(data: new ResponseData(true, string.Join("|", post.images), String.Format(tt.Get("success_post_updated"), tt.Get("static_page") + " (" + post.id + ")")));

    } // End of the images method

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "Administrator")]
    public async Task<IActionResult> delete(IFormCollection collection)
    {
        // Get the current domain
        WebDomain current_domain = await this.web_domain_repository.GetCurrentDomain(ControllerContext.HttpContext);

        // Get translated texts
        KeyStringList tt = await this.static_text_repository.GetFromCache(current_domain.back_end_language_code);

        // Get the id 
        string id = collection["id"].ToString();

        // Get the post
        ModelItem<StaticPageDocument> page_model = await this.static_page_repository.GetById(id);

        // Remove images
        foreach(string src in page_model.item.images)
        {
            // Delete the image
            await this.blob_storage_repository.Delete("media", src);
        }

        // Try to delete a post
        bool success = await this.static_page_repository.DeleteOnId(id);

        // Return an error response
        if (success == false)
        {
            return Json(data: new ResponseData(false, "", String.Format(tt.Get("error_delete_post"), tt.Get("static_page") + " (" + id + ")")));
        }

        // Return a success response
        return Json(data: new ResponseData(true, id.ToString(), String.Format(tt.Get("success_delete_post"), tt.Get("static_page") + " (" + id + ")")));

    } // End of the delete method

    #endregion

    #region Validation

    public async Task<ResponseData> verify_page_name(KeyStringList tt, string id = "", string page_name = "")
    {
        // Get the current domain
        WebDomain current_domain = await this.web_domain_repository.GetCurrentDomain(ControllerContext.HttpContext);

        // Make sure that there is a page_name
        if (page_name == "")
        {
            return new ResponseData(false, "", String.Format(tt.Get("error_field_required"), tt.Get("page_name")));
        }

        // Check for invalid characters
        if (DataValidation.CheckPageNameCharacters(page_name) == false)
        {
            return new ResponseData(false, "", String.Format(tt.Get("error_field_bad_chars"), tt.Get("page_name")));
        }

        // Get a static page on page name
        ModelItem<StaticPagePost> page_name_model = await this.static_page_repository.GetByPageName(page_name, current_domain.back_end_language_code);

        // Check if the page name exists already
        if (page_name_model.item != null && id != page_name_model.item.id)
        {
            return new ResponseData(false, "", String.Format(tt.Get("error_field_unique"), tt.Get("page_name")));
        }

        // Return a success response
        return new ResponseData(true, id, "");

    } // End of the verify_page_name method

    #endregion

    #region Ajax methods

    [HttpPost]
    public async Task<IActionResult> index_list(IFormCollection collection)
    {
        // Get objects
        WebDomain current_domain = await this.web_domain_repository.GetCurrentDomain(ControllerContext.HttpContext);
        KeyStringList tt = await this.static_text_repository.GetFromCache(current_domain.back_end_language_code);

        // Get the form data
        string kw = collection["kw"].ToString();
        string sf = collection["sf"].ToString();
        string so = collection["so"].ToString();
        Int32 pz = Convert.ToInt32(collection["pz"].ToString());
        string ct = collection["ct"].ToString();

        // Get posts by keywords in a search
        ModelPage<StaticPageMeta> static_pages_page = await this.static_page_repository.GetBySearch(kw, current_domain.back_end_language_code, sf, so, pz, ct);

        // Add data to the form
        ViewBag.CurrentDomain = current_domain;
        ViewBag.TranslatedTexts = tt;
        ViewBag.CultureInfo = Tools.GetCultureInfo(current_domain.back_end_language_code, current_domain.country_code);
        ViewBag.Items = static_pages_page.items;
        ViewBag.Continuation = static_pages_page.ct;

        // Return the partial view
        return PartialView("/Views/admin_static_pages/_index_list.cshtml");

    } // End of the index_list method

    #endregion

} // End of the class

Vy

Den här vyn används för att lägga till och uppdatera statiska sidor. Formuläret skickas med ajax, ersätt knappkontrollen (button) med en inlämningskontroll (submit) om du vill skicka formuläret direkt till controllern. Formulär skickas till webbadressen i action-attributet.

@{
    // Set the layout for the page
    Layout = "/Views/shared_admin/_standard_layout.cshtml";

    // Get form data
    WebDomain current_domain = ViewBag.CurrentDomain;
    KeyStringList tt = ViewBag.TranslatedTexts;
    Int32 authorizationLevel = ViewBag.AuthorizationLevel;
    StaticPageDocument post = ViewBag.Post;
    StaticPageDetail spd = post.GetTranslation(current_domain.back_end_language_code);

    // Set texts
    string static_page_tt = tt.Get("static_page");
    string new_tt = tt.Get("new");
    string edit_tt = tt.Get("edit");
    string id_tt = tt.Get("id");
    string connection_tt = tt.Get("connection");
    string no_connection_tt = tt.Get("no_connection");
    string start_page_tt = tt.Get("start_page");
    string error_tt = tt.Get("error");
    string terms_of_service_tt = tt.Get("terms_of_service");
    string privacy_policy_tt = tt.Get("privacy_policy");
    string about_us_tt = tt.Get("about_us");
    string contact_us_tt = tt.Get("contact_us");
    string api_tt = tt.Get("api");
    string standards_tt = tt.Get("standards");
    string editor_tt = tt.Get("editor");
    string blog_tt = tt.Get("blog");
    string validate_tt = tt.Get("validate");
    string show_as_page_tt = tt.Get("show_as_page");
    string keywords_tt = tt.Get("keywords");
    string page_name_tt = tt.Get("page_name");
    string linkname_tt = tt.Get("linkname");
    string title_tt = tt.Get("title");
    string text_html_tt = tt.Get("text_html");
    string meta_description_tt = tt.Get("meta_description");
    string meta_keywords_tt = tt.Get("meta_keywords");
    string meta_robots_tt = tt.Get("meta_robots");
    string save_tt = tt.Get("save");
    string cancel_tt = tt.Get("cancel");

    string main_image_tt = tt.Get("main_image");
    string images_tt = tt.Get("images");
    string upload_tt = tt.Get("upload");
    string delete_tt = tt.Get("delete");


    // Set the title for the page
    if (post.translations.Count == 0)
    {
        ViewBag.Title = static_page_tt + " - " + new_tt.ToLower();
    }
    else
    {
        ViewBag.Title = static_page_tt + " - " + edit_tt.ToLower();
    }
}

@*Title*@
<h1>@ViewBag.Title</h1>

@*Menu*@
@await Html.PartialAsync("/Views/admin_static_pages/_form_menu.cshtml")

@*Main form*@
<form id="inputForm" action="/admin_static_pages/edit" method="post" enctype="multipart/form-data">

    @*Hidden data*@
    <input id="authorizationLevel" type="hidden" value="@authorizationLevel.ToString()" />
    <input id="errorNotUnique" type="hidden" value="@tt.Get("error_field_unique")" />
    <input id="errorNotAuthorized" type="hidden" value="@tt.Get("error_not_authorized")" />
    @Html.AntiForgeryToken()

    @*Input form*@
    <div class="annytab-form-label">@id_tt</div>
    <input id="txtId" name="txtId" type="text" class="annytab-form-control" tabindex="-1" readonly value="@post.id" />

    <div class="annytab-form-label">@connection_tt</div>
    <select id="selectConnection" name="selectConnection" class="annytab-form-control">
        <!option value="0" @(post.connection_id == 0 ? "selected" : "")>@no_connection_tt</!option>
        <!option value="1" @(post.connection_id == 1 ? "selected" : "")>@start_page_tt</!option>
        <!option value="2" @(post.connection_id == 2 ? "selected" : "")>@error_tt</!option>
        <!option value="3" @(post.connection_id == 3 ? "selected" : "")>@terms_of_service_tt</!option>
        <!option value="4" @(post.connection_id == 4 ? "selected" : "")>@privacy_policy_tt</!option>
        <!option value="5" @(post.connection_id == 5 ? "selected" : "")>@about_us_tt</!option>
        <!option value="6" @(post.connection_id == 6 ? "selected" : "")>@contact_us_tt</!option>
        <!option value="7" @(post.connection_id == 7 ? "selected" : "")>@api_tt</!option>
        <!option value="8" @(post.connection_id == 8 ? "selected" : "")>@standards_tt</!option>
        <!option value="9" @(post.connection_id == 9 ? "selected" : "")>@editor_tt</!option>
        <!option value="10" @(post.connection_id == 10 ? "selected" : "")>@blog_tt</!option>
        <!option value="11" @(post.connection_id == 11 ? "selected" : "")>@validate_tt</!option>
    </select>

    <div class="annytab-form-label">@meta_robots_tt</div>
    <select name="selectMetaRobots" class="annytab-form-control">
        <!option value="index, follow" @(post.meta_robots == "index, follow" ? "selected" : "")>index, follow</!option>
        <!option value="index, nofollow" @(post.meta_robots == "index, nofollow" ? "selected" : "")>index, nofollow</!option>
        <!option value="noindex, follow" @(post.meta_robots == "noindex, follow" ? "selected" : "")>noindex, follow</!option>
        <!option value="noindex, nofollow" @(post.meta_robots == "noindex, nofollow" ? "selected" : "")>noindex, nofollow</!option>
    </select>

    <div class="annytab-form-label">@show_as_page_tt</div>
    <div class="annytab-input-group">
        <div class="input-group-cell" style="width:40px;border-right:1px solid #d9d9d9;">
            <input name="cbShowAsPage" type="checkbox" class="annytab-form-checkbox" value="1" @(post != null && post.show_as_page == 1 ? "checked" : "") />
        </div>
        <div class="input-group-cell" style="width:1200px;text-align:left;padding-left:5px;">
            <div class="input-group-control">@show_as_page_tt</div>
        </div>
    </div>

    <div class="annytab-form-label">@page_name_tt</div>
    <input name="txtPageName" type="text" class="annytab-form-control" value="@post.page_name" data-val="true" data-val-required="@String.Format(tt.Get("error_field_required"), page_name_tt)" />
    <div class="field-validation-valid" data-valmsg-for="txtPageName" data-valmsg-replace="true"></div>

    <div class="annytab-form-label">@main_image_tt</div>
    <input name="txtMainImage" type="text" class="annytab-form-control" value="@post.main_image" />

    <div class="annytab-form-label">@keywords_tt</div>
    <textarea name="txtKeywords" class="annytab-form-control" rows="3">@string.Join(",", post.keywords)</textarea>
    <div class="field-validation-valid" data-valmsg-for="txtKeywords" data-valmsg-replace="true"></div>

    <div class="annytab-form-label">@linkname_tt</div>
    <input name="txtLinkName" type="text" class="annytab-form-control" value="@spd.link_name" data-val="true" data-val-required="@String.Format(tt.Get("error_field_required"), linkname_tt)" />
    <div class="field-validation-valid" data-valmsg-for="txtLinkName" data-valmsg-replace="true"></div>

    <div class="annytab-form-label">@title_tt</div>
    <input name="txtTitle" type="text" class="annytab-form-control" value="@spd.title" data-val="true" data-val-required="@String.Format(tt.Get("error_field_required"), title_tt)" />
    <div class="field-validation-valid" data-valmsg-for="txtTitle" data-valmsg-replace="true"></div>

    <div class="annytab-form-label">@text_html_tt</div>
    <textarea name="txtTextHtml" class="annytab-form-control" rows="10">@spd.text_html</textarea>
    <div class="field-validation-valid" data-valmsg-for="txtTextHtml" data-valmsg-replace="true"></div>

    <div class="annytab-form-label">@meta_description_tt</div>
    <textarea name="txtMetaDescription" class="annytab-form-control" rows="5">@spd.meta_description</textarea>
    <div class="field-validation-valid" data-valmsg-for="txtMetaDescription" data-valmsg-replace="true"></div>

    <div class="annytab-form-label">@meta_keywords_tt</div>
    <textarea name="txtMetaKeywords" class="annytab-form-control" rows="5">@spd.meta_keywords</textarea>
    <div class="field-validation-valid" data-valmsg-for="txtMetaKeywords" data-valmsg-replace="true"></div>

    <div class="annytab-basic-space"></div>

    @*Button panel*@
    <div class="annytab-form-button-container">
        <input type="button" class="annytab-form-button" value="@save_tt" onclick="submitForm($('#inputForm'))" />
        <a href="/admin_static_pages" class="annytab-form-button">@cancel_tt</a>
    </div>

</form>

<form id="imageForm" action="/admin_static_pages/images" method="post" enctype="multipart/form-data">

    @*Hidden data*@
    <input name="txtId" type="hidden" value="@post.id" />
    @Html.AntiForgeryToken()

    @*Input form*@
    <div class="annytab-form-label">@images_tt</div>
    <input id="fuImages" name="fuImages" type="file" class="annytab-form-control" multiple />

    <div id="imageContainer">
        @foreach (string src in post.images)
        {
            <div style="margin-top:20px;">
                <img src="@("https://mysite.blob.core.windows.net/media/" + src)" class="annytab-form-image" /><br />
                <span class="annytab-basic-bread-text">@("https://mysite.blob.core.windows.net/media/" + src) - <i class="far fa-trash-alt annytab-basic-link remove-image"></i></span>
                <input name="txtImageSrc" type="hidden" value="@src" />
            </div>
        }
    </div>

    <div class="annytab-basic-space"></div>

    @*Button panel*@
    <div class="annytab-form-button-container">
        <input type="button" class="annytab-form-button" value="@save_tt" onclick="uploadImages($('#imageForm'))" />
    </div>

</form>

@section scripts {
    <script type="text/javascript">

        // Set default focus
        $("#selectConnection").focus();

        $(document).on('click', '.remove-image', function () {
            $(this).parent().parent().remove();
        });

        // Submit the form
        function uploadImages(form)
        {
            // Get form data
            var form_data = new FormData(form[0]);

            $.ajax({
                type: 'POST',
                url: form.attr('action'),
                dataType: 'json',
                data: form_data,
                processData: false,
                contentType: false,
                success: function (data) {
                    if (data.success === true) {
                        $('#imageContainer').html('');
                        var images = data.id != "" ? data.id.split('|') : null;
                        for (var i in images)
                        {
                            $('#imageContainer').append('<div style="margin-top:20px;"><img src="https://mysite.blob.core.windows.net/media/'
                                + images[i] + '" class="annytab-form-image" /><br /><span class="annytab-basic-bread-text">https://mysite.blob.core.windows.net/media/'
                                + images[i] + ' - <i class="far fa-trash-alt annytab-basic-link remove-image"></i></span><input name="txtImageSrc" type="hidden" value="'
                                + images[i] + '" /></div>');
                        }
                        toastr['success'](data.message);
                    }
                    else
                    {
                        toastr['error'](data.message);
                    }
                    $('#fuImages').val('');
                }
            });

        } // End of the uploadImages method
    </script>
}

Skicka formulär utan ajax

För att skicka in ett formulär utan ajax/javascript måste du ha en inlämningsknapp (submit) i formuläret. Formuläret skickas till den url som anges i attributet action.

<input type="submit" class="form-button" value="Save" />

Skicka formulär med ajax

För att skicka in ett formulär med ajax behöver vi en knapp med en onclick-händelse och en metod för att skicka formuläret till angiven url. Du kan avaktivera knappen efter ett klick om du vill förhindra att formuläret skickas in flera gånger.

<input type="button" class="annytab-form-button" value="Save" onclick="submitForm($('#inputForm'))" />
function submitForm(form)
{
    // Make sure that the form is valid
    if (form.valid() === false) { return false; }

    // Get form data
    var form_data = new FormData(form[0]);

    $.ajax({
        type: 'POST',
        url: form.attr('action'),
        dataType: 'json',
        data: form_data,
        processData: false,
        contentType: false,
        success: function (data) {
            if (data.success === true) {
                if (data.url !== "") {
                    location.href = data.url;
                }
                else {
                    toastr['success'](data.message);
                }
            }
            else {
                toastr['error'](data.message);
            }
        }
    });

} // End of the submitForm method

Lämna ett svar

E-postadressen publiceras inte. Obligatoriska fält är märkta *