Hi I'm new to MVC so please bear with me.
I'm trying to do a simple ajax form that just accepts inserts and lets the user know the record has been saved off into a DB.
My problem is two fold.
The data is being inserted into the DB twice
The editors don't get cleared and the message isn't displayed.
I can get this working using straight HTML form posts but wanted to use ajax and then introduce some sort of loading gif or use spin.js.
my code:
_Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>#ViewBag.Title</title>
#Styles.Render("~/Content/css")
#Styles.Render("~/Content/kendo")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/kendo")
#Scripts.Render("~/bundles/jqueryval")
</head>
<body>
<div id="wrapper" style="width:100%; text-align:center">
<img src="~/Content/Header.PNG" alt="MyHeader" />
</div>
#RenderBody()
#RenderSection("scripts", required: false)
</body>
</html>
AboutController
public class AboutController : Controller
{
private readonly IMailRepository repository;
public AboutController(IMailRepository repo)
{
repository = repo;
}
public ActionResult AboutUs()
{
return View();
}
public ActionResult CreateMailing()
{
return View(new MailRequest());
}
[HttpPost]
public PartialViewResult CreateMailing(MailRequest model)
{
if (model == null)
{
return PartialView("_MailingData",new MailRequest());
}
if (ModelState.IsValid)
{
repository.SaveMailRequest(model);
ModelState.Clear();
TempData["message"] = string.Format("{0} has been added to the mailing list.", model.Email);
return PartialView("_MailingData",new MailRequest());
}
else
{
return PartialView("_MailingData",model);
}
}
}
_MailingDate.cshtml
#model MyProj.Models.MailRequest
#Html.EditorForModel()
<br/>
<input type="submit" value="Save"/>
<input type="button" value="Cancel"
onclick="location.href='#Url.Action("AboutUs", "About")' " />
#if (TempData["message"] != null)
{
<div>#TempData["message"]</div>
}
CreateMailing.cshtml
#model MyProj.Models.MailRequest
#{
ViewBag.Title = "Mailing List";
AjaxOptions ajaxOpts = new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "ajaxreplace"
};
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Mailing List Request</title>
</head>
<body>
<div id="ajaxrequest">
#using (Ajax.BeginForm(ajaxOpts))
{
#Html.Partial("_MailingData")
}
</div>
</body>
</html>
----UPDATE
Here is my BundleConfig.cs
public static class BundleConfig
{
// For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
public static void RegisterBundles(BundleCollection bundles)
{
if (bundles == null) return;
// The jQuery bundle
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
//bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
// "~/Scripts/jquery-{version}.js",
// "~/Scripts/jquery-migrate-1.1.1.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
"~/Scripts/jquery-ui-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.unobtrusive*",
"~/Scripts/jquery.validate*"));
// The Kendo JavaScript bundle
bundles.Add(new ScriptBundle("~/bundles/kendo").Include(
"~/Scripts/kendo.all.min.js",
// or kendo.all.min.js if you want to use Kendo UI Web and Kendo UI DataViz
"~/Scripts/kendo.aspnetmvc.min.js"));
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));
bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
"~/Content/themes/base/jquery.ui.core.css",
"~/Content/themes/base/jquery.ui.resizable.css",
"~/Content/themes/base/jquery.ui.selectable.css",
"~/Content/themes/base/jquery.ui.accordion.css",
"~/Content/themes/base/jquery.ui.autocomplete.css",
"~/Content/themes/base/jquery.ui.button.css",
"~/Content/themes/base/jquery.ui.dialog.css",
"~/Content/themes/base/jquery.ui.slider.css",
"~/Content/themes/base/jquery.ui.tabs.css",
"~/Content/themes/base/jquery.ui.datepicker.css",
"~/Content/themes/base/jquery.ui.progressbar.css",
"~/Content/themes/base/jquery.ui.theme.css"));
// The Kendo CSS bundle
bundles.Add(new StyleBundle("~/Content/kendo").Include(
"~/Content/kendo.common.*",
"~/Content/kendo.uniform.*"));
// Clear all items from the ignore list to allow minified CSS and JavaScript files in debug mode
bundles.IgnoreList.Clear();
// Add back the default ignore list rules sans the ones which affect minified files and debug mode
bundles.IgnoreList.Ignore("*.intellisense.js");
bundles.IgnoreList.Ignore("*-vsdoc.js");
bundles.IgnoreList.Ignore("*.debug.js", OptimizationMode.WhenEnabled);
}
}
I think my DB issue may have something to do with the fact I end up with the following in the html of my page
<script src="/bundles/modernizr"></script>
<script src="/Scripts/jquery-2.0.0.js"></script>
<script src="/Scripts/jquery-2.0.3.js"></script>
<script src="/Scripts/kendo.all.min.js"></script>
<script src="/Scripts/kendo.aspnetmvc.min.js"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.min.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js"></script>
I'm guessing I shouldn't have both the full and min js scripts registered but am not sure the best way to prevent this whilst still using bundles
My EFMailRepository
public class EFMailRepository : IMailRepository, IDisposable
{
private EFDbContext context = new EFDbContext();
public void SaveMailRequest(MailRequest mailRequest)
{
context.MailingList.Add(mailRequest);
context.SaveChanges();
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// dispose managed resources
context.Dispose();
}
// free native resources
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
You forgot to put an #ajaxreplace div around the partial:
<div id="ajaxrequest">
#using (Ajax.BeginForm(ajaxOpts))
{
<div id="ajaxreplace">
#Html.Partial("_MailingData")
</div>
}
</div>
You have used this id in your AjaxOptions so you should have a corresponding element in your DOM that will get updated by the result of the AJAX request:
AjaxOptions ajaxOpts = new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "ajaxreplace"
};
As far as your first question about the data being inserted twice into the database is concerned, you haven't provided enough details about your DAL layer so that we could be able to further diagnose the issue. Maybe there's something wrong with your repository.SaveMailRequest method.
Related
I'm new to asp.net core. I have created some razor pages and I want to redirect them by button click events. I have a login page, and I want to redirect to another cshtml page when user clicks on the submit button. This is my Login.cshtml code:
#page "/"
#model Food_Reservation.Pages.Login.LoginModel
#{
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>صفحه ورود</title>
<link href="~/css/Shared.css" , rel="stylesheet" type="text/css" runat="server" />
<link href="~/css/LoginCSS/Login.css" , rel="stylesheet" type="text/css" runat="server" />
<script src="~/js/Login/Login.js" type="text/javascript" language="javascript" defer></script>
</head>
<body>
<main>
<form id="login-form" action="" method="post">
<section id="userpass">
<ul>
<li>
<label for="userId">username</label>
<input type="text"
name="user-name"
id="userId"
class="ltr"
required />
</li>
<li>
<label for="password">password</label>
<input type="password"
name="pass"
id="password"
class="ltr"
required />
</li>
</ul>
</section>
<section>
<button id="enter-btn" runat="server" onclick="RedirectPage();">Enter</button>
</section>
</form>
</main>
</body>
</html>
}
I have write some code in Login.cshtml.cs file, but not working:
namespace Food_Reservation.Pages.Login
{
public class LoginModel : PageModel
{
public void RedirectPage()
{
Response.Redirect("~/Food/Index.cshtml");
}
}
}
Also I write in javascript file:
void RedirectPage()
{
return Redirect("~/Food/Index.cshtml");
}
Still not working...
What is wrong here?
I have tried to redirect to another ".cshtml" file, on click event of a button, but it didn't work.
I have tried to redirect from one ".cshtml" file to the other one, on a button click event, but it doesn't work. It again reloads the current page.
In PageModel class, It will include an OnGet() method by default to load the page, Similar to HttpGet method in mvc. When you want to submit form in Post method, You need to use OnPost()/OnPostAsync() method to accept this http post request in PageModel class. In your Code, I think you wanna submit the form then do some actions finally redirect to another Razor page, So you can use RedirectToPage("xx") method.
public void OnGet()
{
}
public IActionResult OnPost()
{
//other code
//redirect to index.cshtml
return RedirectToPage("pagename");
}
There are also some overloads.
More details you can refer to this Microsoft Docs.
using Microsoft.AspNetCore.Mvc;
namespace MyWebApp.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult About()
{
return Redirect("/about");
}
}
}
<button id="enter-btn" runat="server" asp-page="~/Food/Index.cshtml">Enter</button>
I implemented a custom alert system into my .NET 2.2 application using the following guide: https://www.matheus.ro/2017/12/18/how-to-create-a-simple-alert-system-using-tag-helpers-in-asp-net-core-mvc/
This works perfectly when I run it locally, however I deployed to the live server on Azure last night and noticed that none of the alerts were appearing.
What could be the reason for this? I am not sure how to effectively debug this issue.
AlertsTagHelper.cs:
[HtmlTargetElement("alerts")]
public class AlertsTagHelper : TagHelper
{
private const string AlertKey = "SEPMTool.Alert";
[ViewContext]
public ViewContext ViewContext { get; set; }
protected ITempDataDictionary TempData => ViewContext.TempData;
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "div";
if (TempData[AlertKey] == null)
TempData[AlertKey] = JsonConvert.SerializeObject(new HashSet<Alert>());
var alerts = JsonConvert.DeserializeObject<ICollection<Alert>>(TempData[AlertKey].ToString());
var html = string.Empty;
foreach (var alert in alerts)
{
html += $"<div class='alert {alert.Type}' id='inner-alert' role='alert'>" +
$"<button type='button' class='close' data-dismiss='alert' aria-label='Close'>" +
$"<span aria-hidden='true'>×</span>" +
$"</button>" +
$"{alert.Message}" +
$"</div>";
}
output.Content.SetHtmlContent(html);
}
}
AlertExtensions.cs:
public static class AlertExtensions
{
private const string AlertKey = "SEPMTool.Alert";
public static void AddAlertSuccess(this Controller controller, string message)
{
var alerts = GetAlerts(controller);
alerts.Add(new Alert(message, "alert-success"));
controller.TempData[AlertKey] = JsonConvert.SerializeObject(alerts);
}
public static void AddAlertInfo(this Controller controller, string message)
{
var alerts = GetAlerts(controller);
alerts.Add(new Alert(message, "alert-info"));
controller.TempData[AlertKey] = JsonConvert.SerializeObject(alerts);
}
public static void AddAlertWarning(this Controller controller, string message)
{
var alerts = GetAlerts(controller);
alerts.Add(new Alert(message, "alert-warning"));
controller.TempData[AlertKey] = JsonConvert.SerializeObject(alerts);
}
public static void AddAlertDanger(this Controller controller, string message)
{
var alerts = GetAlerts(controller);
alerts.Add(new Alert(message, "alert-danger"));
controller.TempData[AlertKey] = JsonConvert.SerializeObject(alerts);
}
private static ICollection<Alert> GetAlerts(Controller controller)
{
if (controller.TempData[AlertKey] == null)
controller.TempData[AlertKey] = JsonConvert.SerializeObject(new HashSet<Alert>());
ICollection<Alert> alerts = JsonConvert.DeserializeObject<ICollection<Alert>>(controller.TempData[AlertKey].ToString());
if (alerts == null)
{
alerts = new HashSet<Alert>();
}
return alerts;
}
}
Alert.cs:
public class Alert
{
public string Message;
public string Type;
public Alert(string message, string type)
{
Message = message;
Type = type;
}
}
_Layout.cshtml
#using Microsoft.AspNetCore.Hosting
#inject IHostingEnvironment HostingEnvironment
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<meta name="description" content="A Software Engineering Project Management Tool by Ben Hayward">
<title>#ViewBag.Title</title>
<link href="~/assets/img/favicon.ico" rel="icon" type="image/x-icon">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Gothic+A1" rel="stylesheet">
<link href="~/dist/assets/css/theme.css" rel="stylesheet" type="text/css" media="all" />
</head>
<body>
<div class="layout layout-nav-side">
<partial name="_LoginPartial" />
<div class="main-container">
<div id="mainContent" v-cloak>
<partial name="_BreadcrumbBarPartial" />
<alerts></alerts>
#RenderBody()
</div>
</div>
</div>
<script type="text/javascript" src="~/assets/js/jquery.min.js"></script>
<script type="text/javascript" src="~/assets/js/popper.min.js"></script>
<script type="text/javascript" src="~/dist/assets/js/bootstrap.js"></script>
<script type="text/javascript" src="~/assets/js/autosize.min.js"></script>
<script type="text/javascript" src="~/assets/js/flatpickr.min.js"></script>
<script type="text/javascript" src="~/assets/js/prism.js"></script>
<script type="text/javascript" src="~/assets/js/draggable.bundle.legacy.js"></script>
<script type="text/javascript" src="~/assets/js/swap-animation.js"></script>
<script type="text/javascript" src="~/assets/js/dropzone.min.js"></script>
<script type="text/javascript" src="~/assets/js/list.min.js"></script>
<!-- Required theme scripts (Do not remove) -->
<script type="text/javascript" src="~/dist/assets/js/theme.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="~/build/site.js" asp-append-version="true"></script>
#RenderSection("Scripts", required: false)
<script>
var app = new Vue({
el: "#mainContent",
mixins: vueMixins
});
#if (HostingEnvironment.IsDevelopment())
{
#:Vue.config.devtools = true;
}
</script>
</body>
</html>
_ViewImports.cshtml:
#using SEPMTool
#using SEPMTool.Models
#addTagHelper *, SEPMTool
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#addTagHelper "*, cloudscribe.Web.Pagination"
Alert Trigger in Controller:
if (await _context.SaveChangesAsync() > 0)
{
this.AddAlertSuccess($"{projectTask.TaskName} was created successfully");
return RedirectToAction("Details", new { id = projectTask.ProjectId });
}
I found the solution to this issue, it was caused by the consent cookie being required, with no capability for anyone to accept it.
Credit to: #Smurtagh
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
When application deploys on multiple servers, In that case, application may not display message all the time. Above code use tempData
The TempData uses a session variable internally to store data between requests. And Session data will store on a single server. Then you have to make sure one user all request should go on same server. Check your Session affinity / ARR affinity setting in Azure App Service level or Load balancer level.
I am using bootbox.confirm with an ajax call, and I get the confirm box, but my screen is greyed out and I'm unable to select anything.
Here is what it looks like:
My first thought is that maybe my scripts are referenced wrong in _Layout, but I'm not sure:
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
Bundles
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js",
"~/Scripts/moment.js",
"~/Scripts/bootstrap-datetimepicker.js",
"~/Scripts/jquery-ui.js",
"~/Scripts/Scripts.js"
);
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
"~/Scripts/bootstrap.js",
"~/Scripts/bootbox.js",
"~/Scripts/respond.js"));
When inspecting here is what I have:
<body class="modal-open">
<div class="modal-backdrop fade in"></div>
<div class="modal-dialog">...</div>
Here is my script:
$(document).ready(function () {
var table = $("#Table").DataTable();
$("#Table.js-delete").on("click",
function () {
var link = $(this);
$("body").removeClass("modal-open");
bootbox.confirm("Are you sure you want to delete this?",
function (result) {
$(".modal-backdrop").remove();
if (result) {
$.ajax({
url: "/api/Informations/" + $(this).attr("data-id"),
method: "DELETE",
success: function () {
table.row(link.parents("tr")).remove().draw();
link.parents("tr").remove();
}
});
}
});
});
});
please do inspect element check out classes applied to modal and main body in your page,i'm pretty sure this is because modal-backdrop active and stucked
here are few things you can do
1) just add data-dismiss="modal" to button
2)If modal hide or visible, faded background is remained and does not let you click any where you can forcefully remove those by using below piece of code.
first hide your modal div element.
$('modalId').modal('hide');
secondly remove 'modal-open' class from body and '.modal-backdrop' at the end of the page.
$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
This worked for me. You can try this please:
View:
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index58</title>
<script src="~/Scripts/jquery-1.12.4.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="~/Scripts/bootbox.min.js"></script>
<script type="text/javascript">
$(function () {
$("#btn").click(function () {
bootbox.confirm("This is the default confirm!",
function (result) {
console.log('This was logged in the callback: ' + result);
});
})
})
</script>
</head>
<body>
<div>
<input type="button" value="ShowModal" id="btn" />
</div>
</body>
</html>
At the moment we have view name 'Self Deposit' and a controller to back it.
The view is a stand alone page that built with partial views:
Example
Folder name: SelfDeposit
Main View file: _LayoutSelfDeposit.cshtml
Partial Views: Register.cshtml, Pending.cshtml etc.
This is the main view:
<html dir="#(System.Globalization.CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft ? "rtl" : "ltr")">
<head>
<meta name="viewport" content="width=device-width" />
<title>#ViewBag.Title</title>
#Styles.Render("~/Content/SelfDeposit_css")
#Scripts.Render("~/bundles/scripts")
#Scripts.Render("~/bundles/bootstrap")
#Scripts.Render("~/bundles/jqueryval")
#if (System.Globalization.CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft)
{
#Styles.Render("~/Content/BootstapRtl_css")
}
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700|PT+Sans" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12 text-center">
</div>
</div>
</div>
#RenderBody()
<div class="container text-center">
<img src="~/Content/SelfDeposit/footer-icons.png" class="img-responsive footer-icons" />
</div>
#Html.Partial("ThirdPartyPixels/GoogleTagManager")
</body>
</html>
This is the controller that loads the start of it:
private readonly ForexDbContext _Db = DbLoader.GetDb();
// GET: SelfDeposit
public ActionResult Index()
{
return RedirectToAction(nameof(this.Register));
}
public async Task<ActionResult> Register()
{
ViewBag.CountryId = await GetCountiesAsync();
var model = new SelfDepositRegistrationViewModel { };
if (TempData[Main.LEAD_REG_DETAILS_FOR_OPEN_ACCOUNT] != null && TempData[Main.LEAD_REG_DETAILS_FOR_OPEN_ACCOUNT] is LeadRegistered)
{
var leadRegistered = TempData[Main.LEAD_REG_DETAILS_FOR_OPEN_ACCOUNT] as LeadRegistered;
ViewBag.LeadRegisteredDetails = leadRegistered;
model.FirstName = leadRegistered.FirstName;
model.LastName = leadRegistered.LastName;
model.Email = leadRegistered.Email;
model.PhoneNumber = leadRegistered.Phone;
model.PhoneCountryCode = leadRegistered.PhoneCountry;
}
return View(model);
}
What i am trying to achieve is to have multiple Views each one with different layout and css but keep the controller the same and not copy it each time i am adding a view.
I have tried the following: Adding a folder under the main folder:
SelfDeposit-->Layout1-->_LayoutSelfDeposit.cshtml
But it didn't work since i couldn't figure the routing problem.
Does anyone have ideas?
Thanks
To return a different view, you can specify the name of the view you want to return and model as follows:
return View("ViewName", yourModel);
To get the absolute path of the view, use:
return View("~/Views/FolderName/ViewName.cshtml");
Or you can make a partial view and can return like:
return PartialView("PartialViewName", Model);
I want that my session value check in javascript and if the value is 1 the html button should be invisible in page.
If you use ASP.Net MVC in your controller set the variable that contain button's visibility information (it may be model's var or ViewBag/ViewData var):
public class Default1Controller : Controller
{
public ActionResult Index()
{
ViewBag.isInvisible = true;
return View();
}
}
then in the view:
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script>
$(function() {
var myBool = '#ViewBag.isInvisible';
var isInvisible = (myBool == 'True');
if (isInvisible) {
$('#button').hide();
}
});
</script>
<h2>Index</h2>
<button id="button">#ViewBag.isInvisible</button>
this example requires jquery
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
function HideButton() {
if ('<%=Session["MySession"] %>' == '1') {
$('#' + '<%=MyButton.ClientID %>').css('display', 'none');
$('#MyButton1').css('display', 'none');
}
}
</script>
</head>
<body onload="HideButton();">
<form id="form1" runat="server">
<div>
<asp:Button ID="MyButton" runat="server" Text="Button" />
<input type="submit" title="Save" id="MyButton1" />
</div>
</form>
</body>
</html>
and .cs
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Session["MySession"] = "1";
}
}