Step by step application with partial views - javascript

So I have an application broken down into sections. These sections I put in there own partial views(keep in mind I can do it what ever way is best just though partial view might be that way for content management). I have a main view that contains all of these partials. Now I would like a way to only view one at a time based on a user clicking on a button to go to the next step.
Fill in name
Name:
Steve
button: Next Step
when the client clicks the button next step it will cause the partial view to change from step 1 to step 2. etc etc.
I am having a lot of trouble wrapping my head around this. I have tried calling a viewbag.step = "0" and in the onclick for the buttons doing a javascript for viewbag.step = "1" and in the layout view doing a condition for if viewbag.step == "0" show step 1 if viewbag.step == "1" show step 2 etc etc but that doesn't work because of a reference issue.

You could render a div with an ID within each partial and then have the onclick set the next partial to visible, so to speak. You'd have to include jQuery for this example.
Something like this:
Main CSHTML
#using(Html.BeginForm())
{
#Html.RenderPartial("_PartialView1");
#Html.RenderPartial("_PartialView2");
....
<button onclick="setPage()" >Click me</button>
<script type="text/javascript">
var pageNum = 1;
function setPage()
{
var oldPageId = "#Partial" + pageNum;
pageNum++;
var idToSet = "#Partial" + pageNum;
// toggles visibility
$(oldPageId).toggle();
$(idToSet).toggle();
}
</script>
}
And then your partials like:
<div id="Partial1">
<input type="text" id="Text1"></input>
</div>
<div id="Partial2" style="visibility:hidden">
<input type="text" id="Text2"></input>
</div>
Etc...

Considering you have 3 sections Section 1,Section 2,Section 3.
Write 3 action methods that return partial view.
[HttpPost]
public ActionResult Section1Details(Section1 data,string prevBtn, string nextBtn)
{
if (nextBtn != null)
{
if (ModelState.IsValid)
{
// Do the logic
return View("Section 2");
}
}
return View();
}
[HttpPost]
public ActionResult Section2Details(Section2 data,string prevBtn, string nextBtn)
{
if (prevBtn!=null)
{
// wirte logic here
return View("Section1",bd);
}
if (nextBtn != null)
{
if (ModelState.IsValid)
{
// Do the logic
return View("Section3");
}
}
return View();
}
[HttpPost]
public ActionResult Section3Details(Section3 data,string prevBtn, string nextBtn)
{
if (prevBtn!=null)
{
// wirte logic here
return View("Section2",bd);
}
if (nextBtn != null)
{
if (ModelState.IsValid)
{
// Do the logic
// Save changes
return View("Success");
}
}
return View();
}
In your view,
#using (Html.BeginForm("Section1", "Home", FormMethod.Post))
{
<h1>Step 1 : Basic Details</h1>
#Html.LabelFor(m=>m.Name)<br />
#Html.TextBoxFor(m=>m.Name)
#Html.ValidationMessageFor(m=>m.Name)<br />
<br />
<input type="submit" name="nextBtn" value='Next Step' />
}

Related

"How to 'Reload the only Partial View' part after submitting the form with HTML Helper in jquery?"

I have a partial view on a View of MVC so after Submit the form that is submitting within jquery that you can see below in the code. I have to refresh the Partial view to show some changes that made in partial view after clicking on save button. What should I do in the section of script on click of save?
#using(Html.BeginForm(FormMethod.Post, new{id="form"}))
{
<div>
#Html.Partial("_VehicleCard", Model)
</div>
<div>
<div id="submitBtn" class="row>
#(Model.VehicleCards.Count>0?"":"hidden")">
<div>
<button type="button" id="btnSubmit">Save</button>
</div>
</div>
</div>
}
#section scripts{
<script>
$('#btnSubmit').click(function (event) {
event.preventDefault();
event.stopImmediatePropagation();
$('#form').submit();
//here i wants to refresh Patrial View.
});
</script>
}
Here is my Controller code:
public PartialViewResult GetVehicleForEndMileage(string date, int? Id)
{
try
{
var model = new VehicleEndMilageVM();
DateTime selectedDate;
DateTime.TryParseExact(date, "dd/MM/yyyy", null,
DateTimeStyles.None, out selectedDate);
model.SelectedDate = selectedDate.ToString("dd/MM/yyyy");
model.LocationId = Id ?? 0;
model.VehicleCards =
vehicleDailyInspectionBLL.GetDailyInspectionDetail(selectedDate, Id).Select(x => new VehicleCard
{
VehicleNumber = x.VehicleNumber,
StartMilage = x.StartMilage,
Driver = x.Driver,
EndMilage = x.EndMilage,
VehicleId = x.VehicleId,
VehicleDailyInspectionId = x.VehicleDailyInspectionId,
IsEndMilageAdded = (x.EndMilage !=null && x.EndMilage > 0) ? true : false
}).ToList();
return PartialView("_VehicleCard", model);
}
catch (Exception ex)
{
throw;
}
}
You can simply do it via an ajax call.
First, you have to set an id for <div> tag
<div id="htmlContainer">
#Html.Partial("_VehicleCard", Model)
</div>
Then
$('#btnSubmit').click(function (event) {
event.preventDefault();
event.stopImmediatePropagation();
$('#form').submit();
$.ajax({
url: 'url',
dataType: 'html',
success: function(data) {
$('#htmlContainer').html(data);
}
});
});
You controller seems to be like this :
public PartialViewResult GetVehicleCard(...)
{
return PartialView("_VehicleCard", your view model);
}
HttpPost methods are for SENDING data to the server. You do not need to send your data to the server, rather, you need to GET data from the server with specified criteria and then display it. With that being send, you do not need your HTML.BeginForm() method. Moreover, you do not need to declare a PartialViewResult return type, an ActionResult will suffice. Additionally, you don't need to return the the name of the partial view and the associated model. Simply give the partial view the model results like so:
return PartialView(model)
Next, create an AJAX link on the page you will be clicking your button on like so:
#Ajax.ActionLink("GetVehicleForEndMileage", "Vehicles", new AjaxOptions()
{
HttpMethod = "GET",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "Results"
})
<div id="Results"></div>
You can wrap this link in a button tag to work with your current set-up.
Now just define your Partial View in a separate .cshtml file.
#model ModelName
<div>
// Model attributes to be displayed here.
</div>
Now, embed that partial view within the view you wish to have the callback displayed.
Having said all of that, your javascript/jQuery can be removed.

Prevent javascript firing on load page

I have MVC application with JavaScript in the body of the cshtml page. In Model, I have a method that returns a string, and I want that string to add in some div on a page on click of a button. It works, but, the method is triggered every time I load the page (and I want it to be triggered only on click.
Here is code:
Model:
public class TestJS
{
public string Tekst1 { get; set; }
public string Tekst2 { get; set; }
public TestJS()
{
Tekst1 = "one";
Tekst2 = "two";
}
public string AddTekst()
{
return "three (additional text from method)";
}
}
Controller:
public class TestJSController : Controller
{
// GET: TestJS
public ActionResult Index()
{
Models.TestJS tjs = new Models.TestJS();
return View(tjs);
}
}
View:
#model TestJavaScript.Models.TestJS
#{
ViewBag.Title = "Index";
}
<script type="text/javascript">
function faddtekst() {
whr = document.getElementById("div3");
var t = '#Model.AddTekst()';
whr.innerHTML += t;
}
</script>
<h2>Testing JavaScript Firing</h2>
<p>
First to fields:
#Model.Tekst1;
<br />
#Model.Tekst2;
</p>
<form>
<input type="button" value="Click to show Tekst3" onclick="faddtekst()" />
</form>
<br />
<hr />
<div id="div3">
</div>
I tried to wrap JS in $(document).ready() with same result.
Somebody may think of this as a strange approach, but, a model method that I'm trying to execute takes over 10 seconds in real code, so, I want to prevent waiting every time page loads (waiting should be only if the user clicks button).
The strangest thing is that Model.AddTekst() is executed EVEN if I comment it in javascript function with '//'.
Anyone knows how to avoid unwanted execution of Model.Method?
The behavior you are experiencing is not strange at all. #Model.AddText() executes on the backend once the view is compiled which is normal behaviour.
A comment in razor would look like this
#* Comment goes here *#
But this is not what you want to achieve.
I'm afraid your approach wont work since you can't execute a method on a model asynchronously.
I suggest you take a look at Ajax.BeginForm - more info here
You could implement a controller action on the backend which would return the text you want to display on the submitting of the form.
Try to use e.preventDefault() for button click.
<form>
<input type="button" value="Click to show Tekst3" id="Show" />
</form>
Try with jQuery
$(document).on("click", "#Show", function (e) {
e.preventDefault();
faddtekst();
});

How can I generate a PartialView for each click of a button? [duplicate]

The problem I will be describing is very similar to ones I already found (e.g. this post with nearly identical name) but I hope that I can make it into something that is not a duplicate.
I have created a new ASP.NET MVC 5 application in Visual Studio. Then, I defined two model classes:
public class SearchCriterionModel
{
public string Keyword { get; set; }
}
public class SearchResultModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
}
Then I created the SearchController as follows:
public class SearchController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult DisplaySearchResults()
{
var model = new List<SearchResultModel>
{
new SearchResultModel { Id=1, FirstName="Peter", Surname="Pan" },
new SearchResultModel { Id=2, FirstName="Jane", Surname="Doe" }
};
return PartialView("SearchResults", model);
}
}
as well as views Index.cshtml (strongly typed with SearchCriterionModel as model and template Edit) and SearchResults.cshtml as a partial view with model of type IEnumerable<SearchResultModel> (template List).
This is the Index view:
#model WebApplication1.Models.SearchCriterionModel
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>SearchCriterionModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Keyword, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Keyword, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Keyword, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" id="btnDisplaySearchResults" value="Search" onclick="location.href='#Url.Action("DisplaySearchResults", "SearchController")'" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<div id="searchResults">
</div>
As you can see, I added a div with id="searchResults" below the standard template and edited the button. What I want is to display the partial view SearchResults.cshtml in the div on the bottom, but only after the button is clicked. I have succeeded in showing a partial view there by using #Html.Partial("SearchResults", ViewBag.MyData), but it is rendered when the parent view is loaded for the first time and I set ViewBag.MyData in the Index() method already, which is not what I want.
Summary: On clicking the button, I will obtain some List of SearchResultModel instances (via database access) and then the partial view should be rendered, using this newly obtained data as model. How can I accomplish this? I already seem fail at the first step, that is reacting to the button click with the above code. Right now, I navigate to the URL ~/Search/DisplaySearchResults, but of course there's nothing there and no code-behind method is called.
In traditional ASP.NET I'd just have added a server-side OnClick handler, set the DataSource for a grid and show the grid. But in MVC I already fail with this simple task...
Update: Changing the button to #Html.ActionLink I can finally enter the controller method. But naturally since it returns the partial view, it's displayed as the whole page content. So the question is: How do I tell the partial view to be rendered inside a specific div on the client side?
Change the button to
<button id="search">Search</button>
and add the following script
var url = '#Url.Action("DisplaySearchResults", "Search")';
$('#search').click(function() {
var keyWord = $('#Keyword').val();
$('#searchResults').load(url, { searchText: keyWord });
})
and modify the controller method to accept the search text
public ActionResult DisplaySearchResults(string searchText)
{
var model = // build list based on parameter searchText
return PartialView("SearchResults", model);
}
The jQuery .load method calls your controller method, passing the value of the search text and updates the contents of the <div> with the partial view.
Side note: The use of a <form> tag and #Html.ValidationSummary() and #Html.ValidationMessageFor() are probably not necessary here. Your never returning the Index view so ValidationSummary makes no sense and I assume you want a null search text to return all results, and in any case you do not have any validation attributes for property Keyword so there is nothing to validate.
Edit
Based on OP's comments that SearchCriterionModel will contain multiple properties with validation attributes, then the approach would be to include a submit button and handle the forms .submit() event
<input type="submit" value="Search" />
var url = '#Url.Action("DisplaySearchResults", "Search")';
$('form').submit(function() {
if (!$(this).valid()) {
return false; // prevent the ajax call if validation errors
}
var form = $(this).serialize();
$('#searchResults').load(url, form);
return false; // prevent the default submit action
})
and the controller method would be
public ActionResult DisplaySearchResults(SearchCriterionModel criteria)
{
var model = // build list based on the properties of criteria
return PartialView("SearchResults", model);
}
So here is the controller code.
public IActionResult AddURLTest()
{
return ViewComponent("AddURL");
}
You can load it using JQuery load method.
$(document).ready (function(){
$("#LoadSignIn").click(function(){
$('#UserControl').load("/Home/AddURLTest");
});
});
source code link

Client-server searching with jQuery and MVC

I have a view with two drop downlist which is used to search the description. The list of results are displayed in another view for now. I wish to generate the results in the same search view. I assume some AJAX or Jquery can be used to sort this out but don't know how. So, in this case how can the search result be displayed in the same view page?
Moreover, i have some doubt in Search controller. I want at least one drop down list to be selected (Both drop down list shouldn't be allowed null). How can i validate that part?
View
#using (Html.BeginForm("Search","Work",FormMethod.Get))
{
<fieldset>
<legend>Search</legend>
<div class="editor-label">
#Html.LabelFor(model => model.JobTypeID, "Job Type")
</div>
<div class="editor-field">
#Html.DropDownList("JobTypeID", "Select Job Type")
</div>
<div class="editor-label">
#Html.LabelFor(model => model.JobPriorityID, "Job Priority")
</div>
<div class="editor-field">
#Html.DropDownList("JobPriorityID", "Select Job Priority")
</div>
<p>
<input type="submit" value="Search" />
</p>
</fieldset>
}
Controller:
[HttpGet]
public ActionResult Search(int? jobtypeid, int? jobpriorityid)
{
var vJobDescriptions = new List<JobDescription>();
if (jobtypeid != null && jobpriorityid != null )
{
vJobDescriptions = (from description in db.JobDescriptions
where (description.JobTypeID == jobtypeid && description.JobPriorityID == jobpriorityid)
select description).ToList();
}
else if (jobtypeid == null && jobpriorityid != null)
{
vJobDescriptions = (from description in db.JobDescriptions
where (description.JobPriorityID == jobpriorityid)
select description).ToList();
}
else if (jobtypeid != null && jobpriorityid == null)
{
vJobDescriptions = (from description in db.JobDescriptions
where (description.JobTypeID == jobtypeid)
select description).ToList();
}
else
{
vJobDescriptions = (from description in db.JobDescriptions
select description).ToList();
}
return View(vJobDescriptions);
}
One possibility is to use an Ajax.BeginForm instead of a normal form (don't forget to include jquery.js and jquery.unobtrusive-ajax.js scripts to your page):
#using (Ajax.BeginForm("Search", "Work", new AjaxOptions { UpdateTargetId = "results" }))
then you could have a placeholder for the results that we specified in the UpdateTargetId:
<div id="results"></div>
Now all that's left is to have your Search controller action return a PartialView and pass it the model containing the results of the search:
public ActionResult Search(int? jobtypeid, int? jobpriorityid)
{
var model = ...
return PartialView("_Result", model);
}
and of course the corresponding _Result.cshtml partial:
#model IEnumerable<MyViewModel>
...
Moreover, i have some doubt in Search controller. I want at least one
drop down list to be selected (Both drop down list shouldn't be
allowed null). How can i validate that part?
I would recommend you FluentValidation.NET but if you don't want to use third party libraries you could write a custom validation attribute that will perform this validation and then decorate one of the 2 view model properties that are bound to your dropdown lists with it.
Unfortunately if you decide to go the AJAX route, you will have to be able to display validation errors coming from the server in case there was something wrong. So it is the entire form that has to be put inside the partial.
Another approach that you could use is to simply reload the entire page using a standard form without AJAX. The results will be part of your initial view model as a collection property which will initially be null and after performing the search you will populate it with the results. Then inside the view you will test if the property is not null and if it isn't include the Partial that will take care of rendering the results:
#using (Html.BeginForm("Search", "Work", FormMethod.Get))
{
...
}
<div id="results">
#if (Model.Results != null)
{
#Html.Partial("_Results", Model.Results)
}
</div>
A basic approach to this would be to place the markup for your search results into a partial view, and return that from your Search ActionMethod. This would require you to change the last line of your search method to
return Partial(vJobDescriptions)
In your client-side script, you would do something along the lines of this:
var data = $("form").serialize();
$.get("/Search", data)
.complete(function(results) {
$("form").replace(results) };
With regards to the validation aspect you're looking for, I would consider separating your read model from the search command parameters.
public ActionResult Search(SearchModel search)
{
if (!ModelState.IsValid) // return view w/ invalid model
}
where your search params model would be along these lines:
[CustomValidation(typeof(SearchModel),
"OneNotNullValidator",
"One option must be selected"]
public class SearchModel
{
public int? JobTypeID { get; set;}
public int? JobPriorityID { get; set;}
public bool OneNotNullValidator()
{
return JobTypeID.HasValue || JobPriorityID.HasValue;
}
}
The CustomValidation attribute I've applied to the class may not be 100% correct on the specific syntax and name(s), but I hope the gist of it comes across.

Dynamic created checkbox using foreach in asp.net mvc

I have list page to show all images with its name from database in asp.net mvc list action (PhotoList - get).. in that view page (PhotoList.aspx), I have created checkbox to delete multiple rows. I want scenario like following
First page shows the list with in first column checkbox and in second column PhotoName and on the down page one button for delete selected rows .
when selects checkboxes and clicks the delete button, according to selection the rows will be deleted from database and return the same list page..
I don't understand where to write code for delete and how?
<% foreach (var item in Model) { %>
<tr>
<td>
<input type="checkbox" name="deleteImage" value="<%= item.PhotoId %>"/>
</td>
<td>
<%= Html.ActionLink("Edit", "Edit", new { id=item.PhotoId }) %>
</td>
<td>
<%= Html.Encode(item.PhotoName) %>
</td>
</tr>
<% } %>
<input type="button" name="Delete" value="Delete Selected items"/>
The Code for delete will be written in the HttpPost action for delete. Something like below should work if you are using myModel
[HttpPost]
public ActionResult Delete(myModel deleteEntries) //This is the post-version of your Action that rendered the view..If it's Edit, then change the name to Edit
{
var deleteList = db.deleteEntries.where(d => d.checkBox == true).ToList();
foreach (myList my in deleteList)
{
db.myList.Remove(my); // remember db should be your DbContext instace
}
db.SaveChanges();
}
UPDATE
You will first need to make a ViewModel because otherwise you cannot recognize which entries are checked for deletion with the help of checkbox.
Make a ViewMode class like following
using pratice3.Models;
public class MyPhotoViewModel
{
public UserManagementDbEntities.tblPhoto TablePhoto { get; set; }
public bool checkBox { get; set; }
}
Return this to your view
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult PhotosList()
{
var viewModel = _datamodel.tblPhoto.Select(g => new MyPhotoViewModel
{
TablePhoto = g;
checkBox = false;
}).ToList();
return View(viewModel);
}
In View, change the using statement to reflect IEnumerable<MyPhotoViewModel> and make appropriate changes accordingly.
Then, define your Post Action like following
[HttpPost]
public ActionResult PhotosList(IEnumerable<MyPhotoViewModel> myPhotoList)
{
var deleteList = myPhotoList.where(d => d.checkBox == true).ToList();
foreach (var deletePhoto in deleteList)
{
_datamodel.tblPhoto.DeleteObject(deletePhoto.TablePhoto);
}
db.SaveChanges();
}
Using jQuery you can do this.
On button click get all the Ids of photos, something like this
var selected = new Array();
$('name="deleteImage" input:checked').each(function () {
selected.push($(this).attr('id')));
});
var selectedIds = selected.join(',');
Now on button click, make ajax call to some function on server side which will accept these ids and will delete from DB or so.
$.ajax({
url: '#Url.Action("DeleteRecord", "UserManage")',
data: 'ids=' + selectedIds + '&time=' + new Date(), //Date makes each call unique
success: function (data) {
//You can reload page
},
error: function (data) {
//You can show error
}
});
Hope this helps.

Categories