This article is about forms in ASP.NET Core, how to validate them and how to post the data. The purpose of a form is to take input data, validate this data and save the data in a database.
To create and post a form in ASP.NET Core you need a View, a Controller and a Model. You can submit the form directly to the controller or use ajax/javascript to submit the form to a controller. Form validation is usually done with a combination of javascript and controller methods.
Form encoding
Form data can be encoded in 3 different ways, the type used is specified in the enctype attribute in the form tag.
application/x-www-form-urlencoded: Data is sent as key-value-pairs and all data is encoded.
multipart/form-data: Data is sent as sections and no data is encoded. This type must be used if you have a file upload control in your form.
text/plain: Data is sent as it is, no encoding. Can be used to send a JSON-document or an XML-document.
Libraries
We need some jquery/javascript libraries to be able to handle our form. These libraries is imported in our standard layout view, it is convient to import all libraries in one place. Jquery is used to post the form with ajax and is used in validation. Toastr is used to show small messages to the user and Font Awesome is used to get nice icons. Jquery validation and Jquery validate unobtrusive is used to validate the form.
<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>
Models
The main models for our form is ResponseData, StaticPageDocument and StaticPageDetail. ResponseData is used to display messages to the user and the other two models is important to display and save data in the form.
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
This controller includes methods that we need to administer static pages, it is the link between views and repositories. This controller should return views and handle form postings.
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
View
This view is used to add and update static pages. The form is submitted with ajax, replace the input button with a input submit if you want to submit the form directly to the controller. Forms is posted to the url in the action attribute.
@{
// 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>
}
Submit a form without ajax
To submit a form without ajax/javascript you need to have a submit button in the form. The form is posted to the url in the action attribute.
<input type="submit" class="form-button" value="Save" />
Submit a form with ajax
To submit a form with ajax we need a button with an onclick event and a method to post the form to the action url. You might want to disable the button after a click to prevent the form from being posted multiple times.
<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