Coming from WebForms getting my head around some MVC stuff is not quite intuitive and I am struggling to find a way to modal to pop-up from the controller (depending upon the postback result)..
The modal
<div id="PopupModal" class="modal fade in out">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" aria-hidden="true" type="button" data-dismiss="modal">×</button>
<h4 class="modal-title" id="ModalTitle"></h4>
</div>
<div class="modal-body" id="ModalBody">
<h5 id="ModalBodyText"></h5>
</div>
<div class="modal-footer">
<button class="btn btn-default" type="button" data-dismiss="modal">Close</button>
</div>
</div>
</div>
This is how I would have raised the event in WebForms
Private Sub ModalValidation(Message As String)
Try
Dim SB As New StringBuilder
SB.Append("$(document).ready(function(){")
SB.Append("$('#PopupModal').modal();")
SB.Append("var vBody = document.getElementById('ModalBodyText');")
SB.Append("vBody.innerHTML = '" & Message & "';")
SB.Append("var vTitle = document.getElementById('ModalTitle');")
SB.Append("vTitle.innerHTML = 'Validation';")
SB.Append("vTitle.style.color = 'orange';")
SB.Append("});")
ScriptManager.RegisterStartupScript(Me, Me.GetType(), "ValidationShowModal", SB.ToString, True)
Catch ex As Exception
Dim vError As New SendError
vError.MailError(60, PageName, ex)
End Try
End Sub
How can I raise the same event from the controller?
Thanks
Edit = Big thank you to Vitor Salgado for pointing me in the right direction
Added this to the controller - Index
Function Index() As ActionResult
Dim vPopup As New UploadFilesResult
If Not Session("PopupMessage") Is Nothing Then
vPopup.PopupMessage = Session("PopupMessage")
Else
vPopup.PopupMessage = "None"
End If
ViewData("UploadFilesResult") = vPopup
Return View("BlueImpMinView")
End Function
Added this to Controller - ActionResult (where the action completed normally)
Session("PopupMessage") = "The file was successfully uploaded!"
Return Redirect("/blueimp/Index#Completed")
Added a hidden field to the view
#code
Dim vPopup As MVPTest.UploadFilesResult = CType(ViewData("UploadFilesResult"), MVPTest.UploadFilesResult)
Dim vPopupMessage As String = vPopup.PopupMessage
#Html.TextBox("MessageTB", vPopupMessage, New With {.type = "hidden"})
End Code
and the javascript for the modal
<script>
window.onload = function () {
var vType = location.hash;
var vMessage = document.getElementById('MessageTB').value;
switch (vType) {
case '#Completed':
//run code for completed modal
$(document).ready(function () {
$('#PopupModal').modal();
var vBody = document.getElementById('ModalBodyText');
vBody.innerHTML = vMessage;
var vTitle = document.getElementById('ModalTitle');
vTitle.innerHTML = 'Success';
vTitle.style.color = 'green';
});
break;
case '#Error':
//run code for error modal
break;
case '#Validation':
//run code for validation modal
}
}
</script>
In controller code, you could append to your querystring some marker parameter or return a specific cookie, then, in your javascript code, you can identify one of these marker values and show your modal window.
Here some sample code..
The controller
public ActionResult Register()
{
return View();
}
[HttpPost]
public ActionResult Register(RegisterModel model)
{
return Redirect("/Home/Register#registered");
}
The view
#using (Html.BeginForm())
{
<label>Login</label><br />
#Html.TextBoxFor(x => x.Login)
<br />
<label>Name</label><br />
#Html.TextBoxFor(x => x.Name)
<br />
<label>Email</label><br />
#Html.TextBoxFor(x => x.Emai)
<br />
<input type="submit" value="Register" />
}
<script type="text/javascript">
window.onload = function () {
if (window.location.hash == '#registered') {
alert('Your modal code here!');
}
};
</script>
The action Register(POST) is the server side code that will create some marker to your client side code. In the sample, a added a hash value to url. You could return a cookie value or better, add some value to hidden field and read the value from it. In the view, a have simple JS code that executes on page load. The JS search for the hash value and show the modal.
There are several ways to do this that fit within the MVC way of doing things. Here's what I would do...
If you need the server to decide whether or not to show the modal, but you don't wish to refresh the page, then AJAX is probably what you want. Use can use jQuery's ajax calls to post data to a controller action, make a decision on the server, then send back a result that your js can use to either show the modal or not. This way, the page does not need to refresh yet you make a round trip to the server to decide what you need to do.
Related
I have the following code on my cshtml page:
<div class="large reveal" id="draftProductModal" data-reveal>
<button class="close-button" data-close aria-label="Close modal" type="button">
<span aria-hidden="true"><i class="fa fa-times-circle-o"></i></span>
</button>
</div>
<div class="input-group">
<input type="text" class="input-group-field" id="draftSearchProducts" name="draftSearchProducts" placeholder="SearchProducts" />
<div class="input-group-button">
<!--Add product to order lines button-->
<a id="draftAddProduct" class="hollow button secondary" data-open="draftProductModal"><i class="fa fa-plus"></i> Search Products</a>
</div>
</div>
I need to take the value in the draftSearchProducts text field, pass it to a controller that returns a partialview:
public ActionResult SearchResults(string keywords, int queryLimit = 20, int offset = 0)
{
try
{
//connect to db, grab data return results
searchResults.ProductDetails = products.ToList();
return PartialView("_SearchResults", searchResults);
}
catch (Exception ex)
{
throw ex;
}
}
I need to send in the keyword to the controller, return the partial view and load it into the draftProductModal div and display the div. How is this done? I am new to front end development.
Tried this code:
var url = '/ProductsController/SearchResults';
$('#draftAddProduct').click(function () {
var keyWord = $('draftSearchProducts').val();
$('#draftProductModal').load(url, { keywords: keyWord });
});
And all I get is a 404 error, so it appears I am not hitting my controller. I think I am getting close, I just need to find out how to access the controller ActionResult. Still accepting help.
I am new to asp.net MVC 5, I wonder how to use Ajax to call the modal with partial view? i had tried some code but the modal doesn't show up. Any body help?
Here is my code:
View
<script>
#Scripts.Render("~/bundles/jqueryval")
// Create
$(".modalCreate").click(function (e) {
e.preventDefault();
$.ajax({
cache: false,
type: "GET",
url: '#Url.Action("Create","Category")',
success: function () {
$(this).attr('data-target', '#createCat');
$(this).attr('data-toggle', 'modal');
// Attach listener to .modal-close-btn's so that when the button is pressed the modal dialog disappears
$('body').on('click', '.modal-close-btn', function () {
$('#createCat').modal('hide');
});
//clear modal cache, so that new content can be loaded
$('#createCat').on('hidden.bs.modal', function () {
$(this).removeData('bs.modal');
});
$('#CancelModal').on('click', function () {
return false;
});
// Init JQuery Validation for view
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");
},
error: function (xhr, ajaxOptions, thrownError) {
displayAjaxError(thrownError);
}
});
});
</script>
<p>
#Html.ActionLink("Create Category ", "Create", "Category",
null, new { #class = "modalCreate btn btn-success" })
</p>
<div id="createCat" class="modal fade"
tabindex="-1" role="dialog">
<div class="modal-content">
</div>
</div>
This is my controller:
public ActionResult Create()
{
return PartialView("_Create");
}
// POST: /Category/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CategoryCreateVM productcategory)
{
if (ModelState.IsValid)
{
ProductCategory cat = Mapper.Map<CategoryCreateVM, ProductCategory>(productcategory);
db.ProductCategories.Add(cat);
db.SaveChanges();
TempData["Message"] = "New Category added sucessfully.";
ViewBag.Message = "New Category added sucessfully.";
return RedirectToAction("Index");
}
return PartialView(productcategory);
}
and partial view:
<div class="modal-dialog">
<div class="modal-body">
<div class="modal-content">
#using (Html.BeginForm("Create", "Category", FormMethod.Post))
{
}
</div>
</div>
</div>
I using the boostrap default theme to do. I try to debug in browser inspection it doesnt show any error. But I can sure is it able to find my partial view but the modal never show up. I hope that anyone can help me check my code.
if I understand well this is the way:
1- add your Modal Template in "<script>" part of Views->Shared->_Layout whith specific id for each part of modal to use it every where you want, for example:
<!-- Modal start-->
<div class="modal fade" id="Modalid" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close"></button>
<h4 class="modal-title" id="ModalLabelid">Modal title</h4>
</div>
<div class="modal-body" id="ModalBodyid"></div>
</div>
</div>
</div>
<!--Modal End-->
2- then add code below in any view that you want use modal :
<script>
function functionname() {
$("#Modalid").modal();
$("#ModalLabelid").html("YourTitle");
$("#ModalBodyid").load("url of partial view or anything that you want show in modal body");
}
</script>
now if you want load body of modal from some partialview , write the url in .load() method :
$("#ModalBodyid").load("/Controller/Action/");
and if your action should get parameter, add the name of parameter exactly as in action entire :
$("#ModalBodyid").load("/Controller/Action/" + NameOfParameterinAction);
finally to use your script you should call functionname() every where you need from any View :)
I'm trying to learn more about MVC 5 so I'm writing a bloging site for myself to learn more as I go.
I have set up a select list for tags and would like to be able to add new tags from the create blog entry page rather than having to remember to set the tags up before creating a new post. I'm thinking down the lines of a "Add Tag" button which displays a bootstrap modal window where the user can add a new tag.
Here is my controller action:
public ViewResult CreateBlogPost()
{
CreateEditBlogViewModel viewModel = new CreateEditBlogViewModel();
viewModel.BlogPost = new Core.BlogPost();
viewModel.BlogPost.ShortBody = "<p>Something short and sweet to describe the post</p>";
viewModel.BlogPost.Body = "<p>Enter something blog worthy here...</p>";
viewModel.Tags = new SelectList(_blogRepo.BlogTags(), "Id", "Name");
viewModel.Categories = new SelectList(_blogRepo.BlogCategories(), "Id", "Name");
return View(viewModel);
}
And here is the HTML in the view:
<div class="row">
<div class="form-group">
#Html.LabelFor(m => m.BlogPost.Tags, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.ListBoxFor(m => m.SelectedTags, Model.Tags, new { #class = "form-control chosen-select", #data_placeholder = "Start typing to see a list of tags" })
</div>
</div>
</div>
<div class="row">
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#tagModal">
Add Tag
</button>
</div>
Here is my partial view for the modal window:
#using (Html.BeginForm("SaveTag", "Home", FormMethod.Post, new { id = "tag-form" }))
{
#Html.AntiForgeryToken()
<!-- Modal -->
<div class="modal fade" id="tagModal" tabindex="-1" role="dialog" aria-labelledby="tagModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="tagModalLabel">Enter a name for a new tag</h4>
</div>
<div class="modal-body">
<input type="text" id="Name" placeholder="Enter a new tag name" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
}
Is it possible to add a tag on the client side, persist it into the db and then add it to my tags select list without refreshing the page?
PS: FYI I'm using the Chosen multi-select from here.
#section scripts {
<script type="text/javascript" src="~/Scripts/chosen.jquery.min.js"></script>
<script type="text/javascript">
$(".chosen-select").chosen()
</script>
}
EDIT: I have updated the question with all the code that makes the view give the user the modal window to enter a new tag name. I'm just not sure how to post without navigating away from the page so I'm guessing some sort of Ajax post is required. And then what to do with the data that is returned from that post. How do I then add that new persisted record to the select list?
I know the tag isn't passing to the controller method as it's not bound to any sort of model but being as I'm using a view model on the parent view, I'm not sure how I would handle that here either.
In order to dynamically add a new BlogTag in the view you will need to post the new tag Name using ajax, to a controller method that saves the BlogTag and returns its new ID value. Your controller method would be something like
[HttpPost]
public JsonResult CreateTag(string name)
{
BlogTag tag = new BlogTag(){ Name = name };
db.BlogTags.Add(tag);
db.SaveChanges();
return Json(tag.ID);
// If the above code could result in an error/exception, catch it and return
// return Json(null);
}
Then in the view, handle the dialogs submit button to post the value and update the tag list
var url = '#Url.Action("CreateTag")';
var tagList = $('#SelectedTags');
$('#tag-form').submit(function() {
var tagName = $('#Name').val();
$.post(url, { name: tagName }, function(id) {
if (id) {
// add the new tag to the list box
tagList.append($('<option></option>').val(id).text($('#Name').val()));
// trigger the chosen update
tagList.trigger("chosen:updated");
} else {
// Oops - display an error message?
}
}).fail(function (result) {
// Oops - display an error message?
});
return false; // cancel the default submit
});
Side note: I would recommend that you create a view model for BlogTagVM (containing a property for the Name with validation attributes) and an associated partial view (say _AddBlogTag.cshtml) that generates the dialog html, so that in the main view you can use #Html.Partial("_AddBlogTag", new BlogTagVM()) which will allow you to use the strongly typed html helpers, and to include client side validation.
Note also that nested <form> elements are invalid html so ensure that html for the dialog is outside the main <form> tag for the view.
I am doing something similar, I think it might help. In my case, I'm "moving" values from one list to another (from "available" to "used") and then saving the values of the "used" list. Anyway, in the controller, the "used" list shows up as an array of strings. Here's my code:
public ActionResult PinchHit(FormCollection form, LineupViewModel lvm, String[] UsedPlayers)
{
[Snip]
if (ModelState.IsValid && lineupResults.IsValid)
{
[Snip]
foreach (String usedID in UsedPlayers)
{
gameState.HomeUsedPlayersIDs.Add(Convert.ToInt32(usedID));
}
uow.Repository<GameState>().Update(gameState);
uow.SaveChanges();
return RedirectToAction("Index", "GameSummary");
}
[Snip]
return View(lvm2);
}
Hope that helps.
Per my comment:
Here is an AJAX call-back mechanism I used to retrieve data from the database without reloading the page, you could use it to save data to the database instead.
<script type="text/javascript">
function getPositions(id, control) {
$.ajax({
url: "#Url.Action("GetPositions", "Lineup")",
data:
{
id: id
},
dataType: "json",
type: "POST",
error: function () {
alert("An error occurred.");
},
success: function (data) {
$(control).html("");
$.each(data, function (i, item) {
$(control).append("<option value=\"" + item.Value + "\">" + item.Text + "</option>");
}
);
}
});
}
</script>
then in the controller:
[HttpPost]
public ActionResult GetPositions(int id)
{
Player player = uow.Repository<Player>().GetById(id);
if (player == null)
{
return (null);
}
List<SelectListItem> positionList = new SelectList(player.Positions, "ID", "ShortName").ToList();
return Json(positionList);
}
Pretty standard stuff really.
I have a form in ASP.Net and razor.
I need to have two ways of submitting said form: one that goes through the Edit action, and another that goes through the Validate action.
How should I go about doing this?
I don't mind using JavaScript for this.
EDIT:
Using the custom attribute I get this error.
The current request for action 'Resultados' on controller type 'InspecoesController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Validar(System.Collections.Generic.ICollection1[Waveform.IEP.Intus.Server.Web.ViewModels.ResultadoViewModel]) on type Waveform.IEP.Intus.Server.Web.Controllers.InspecoesController
System.Web.Mvc.ActionResult Resultados(System.Collections.Generic.ICollection1[Waveform.IEP.Intus.Server.Web.ViewModels.ResultadoViewModel]) on type Waveform.IEP.Intus.Server.Web.Controllers.InspecoesController
That's what we have in our applications:
Attribute
public class HttpParamActionAttribute : ActionNameSelectorAttribute
{
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;
var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
Actions decorated with it:
[HttpParamAction]
public ActionResult Save(MyModel model)
{
// ...
}
[HttpParamAction]
public ActionResult Publish(MyModel model)
{
// ...
}
HTML/Razor
#using (#Html.BeginForm())
{
<!-- form content here -->
<input type="submit" name="Save" value="Save" />
<input type="submit" name="Publish" value="Publish" />
}
name attribute of submit button should match action/method name
This way you do not have to hard-code urls in javascript
You can do it with jquery, just put two methods to submit for to diffrent urls, for example with this form:
<form id="myForm">
<%-- form data inputs here ---%>
<button id="edit">Edit</button>
<button id="validate">Validate</button>
</form>
you can use this script (make sure it is located in the View, in order to use the Url.Action attribute):
<script type="text/javascript">
$("#edit").click(function() {
var form = $("form#myForm");
form.attr("action", "#Url.Action("Edit","MyController")");
form.submit();
});
$("#validate").click(function() {
var form = $("form#myForm");
form.attr("action", "#Url.Action("Validate","MyController")");
form.submit();
});
</script>
If you are working in asp.net with razor, and you want to control multiple submit button event.then this answer will guide you. Lets for example we have two button, one button will redirect us to "PageA.cshtml" and other will redirect us to "PageB.cshtml".
#{
if (IsPost)
{
if(Request["btn"].Equals("button_A"))
{
Response.Redirect("PageA.cshtml");
}
if(Request["btn"].Equals("button_B"))
{
Response.Redirect("PageB.cshtml");
}
}
}
<form method="post">
<input type="submit" value="button_A" name="btn"/>;
<input type="submit" value="button_B" name="btn"/>;
</form>
Here is a good eplanation:
ASP.NET MVC – Multiple buttons in the same form
In 2 words:
you may analize value of submitted button in yout action
or
make separate actions with your version of ActionMethodSelectorAttribute (which I personaly prefer and suggest).
With HTML5 you can use button[formaction]:
<form action="Edit">
<button type="submit">Submit</button> <!-- Will post to default action "Edit" -->
<button type="submit" formaction="Validate">Validate</button> <!-- Will override default action and post to "Validate -->
</form>
<input type="submit" value="Create" name="button"/>
<input type="submit" value="Reset" name="button" />
write the following code in Controler.
[HttpPost]
public ActionResult Login(string button)
{
switch (button)
{
case "Create":
return RedirectToAction("Deshboard", "Home");
break;
case "Reset":
return RedirectToAction("Login", "Home");
break;
}
return View();
}
We can have this in 2 ways,
Either have 2 form submissions within the same View and having 2 Action methods at the controller but you will need to have the required fields to be submitted with the form to be placed within
ex is given here with code Multiple forms in view asp.net mvc with multiple submit buttons
Or
Have 2 or multiple submit buttons say btnSubmit1 and btnSubmit2 and check on the Action method which button was clicked using the code
if (Request.Form["btnSubmit1"] != null)
{
//
}
if (Request.Form["btnSubmit2"] != null)
{
//
}
have been struggling with this. Tried everything I can think of. Im using javascript to pass data to db, works fine with ints on another page but now with strings it wont work :s
#using (Html.BeginForm(null, null, FormMethod.Post, new{#id="manageForm"}))
{
#Html.AntiForgeryToken()
<span class="actions">
#T(User.Id.ToString()) #T(" ") #T(ViewData["Tag"].ToString())
<input type="hidden" name="tag" value="fr" />
<input type="hidden" name="id" value="3" />
#T("Follow")
</span>
}
Javascript
<script type="text/javascript">
function followTag() {
$('#manageForm').attr('action', '#(Url.Action("FollowTag"))').submit();
return false;
}
</script>
Controller
[RequireAuthorization]
[HttpPost]
public ActionResult FollowTag(int id, string tag)
{
_service.FollowTag(id, tag);
return RedirectToAction("TagPage","Detail", new
{
});
}
Data Access
public void FollowTag(int id, string tag)
{
DbCommand comm = GetCommand("SPTagFollow");
//user id
comm.AddParameter<int>(this.Factory, "id", id);
//id to follow
comm.AddParameter<string>(this.Factory, "tag", tag);
comm.SafeExecuteNonQuery();
}
route is setup fine and sql(stored procedure) executes perfect. Hopefully one of you can see something obvious
cheers
I think is a problem of mistyping, check your last <a> tag, you typed following.() in the onclick event, see that your javascript function is called followTag.
If that doesn't fix it, then get rid of that foolowTag function, you can specify the action and the controller in the form itself, like this:
#using (Html.BeginForm("FollowTag", "YourControllerName", FormMethod.Post)) {
...
//Delete this line
//#T("Follow")
//This submit button will do the job
<input type='submit' value='#T("Follow")' />
}
That should do it. If you are using the anchor tag just for styling that's ok, otherwise you should use the other way, I think is clearer and besides it takes advantage of razor's great features.