I currently have a view page that lists users as a gallery with their image but i also want to create a view page that lists the users by name. I want to use one controller for both of them and i created a ListView page and in the orginial View page which shows users by image - I have a link to view the ListView page. I tried clicking on the link but the page is not showing up. Here is what i have:
Image view page
<h2>Users</h2>
<div>
Click Here for List view
</div>
<section id="Images">
<section id="users" data-bind="foreach: Users">
<div id="nameImage">
<figure id="content">
<img width="158" height="158" alt="Gravatar" data-bind="attr:{src: GravatarUrl}"/>
<figcaption>
...
</figcaption>
</figure>
<p data-bind="text:Name"></p>
</div>
</section>
</section>
#section scripts{
#Scripts.Render("~/bundles/user" + ViewBag.Layout.AppVersionForUrls)
<script type="text/javascript">
(function ($) {
$.views.User.GetUser('#url');
})(jQuery);
</script>
}
List view page
<div class="accordion-inner">
<div data-bind="foreach: Users">
<div>
<img width="158" height="158" alt="Gravatar" data-bind="attr:{src: GravatarUrl}"/>
<p data-bind="text:Name"></p>
</div>
</div>
#section scripts{
#Scripts.Render("~/bundles/user" + ViewBag.Layout.AppVersionForUrls)
<script type="text/javascript">
(function ($) {
$.views.User.GetUser('#url');
})(jQuery);
</script>
}
Controller
public ActionResult View(int id)
{
// get the menu from the cache, by Id
ViewBag.SideBarMenu = SideMenuManager.GetRootMenu(id);
ViewBag.UserApiURL = "/api/User/" + id.ToString();
return View();
}
public ActionResult ListView(int id)
{
// get the menu from the cache, by Id
ViewBag.SideBarMenu = SideMenuManager.GetRootMenu(id);
ViewBag.RosterApiURL = "/api/User/ListView" + id.ToString();
return View();
}
The concept in MVC is that you never link to views, you link to an action in a controller, that then decides (based on parameters passed) which view and with what model should be rendered. So, if your controller is called UsersController, the
Click Here for List view
line should be:
Click Here for List view
or even better
#Html.ActionLink("ListView")
Related
I am creating an ASP.NET Core 3 MVC application that has a Customers tab in addition to the Home tab. On the Customers tab there is an input box where the user adds a search criterion (number of days) and a Search button. When the button is clicked then a list of Customer Ids is shown underneath (using jQuery and a Partial View). When the user clicks on a customer Id then the customer information is shown in a different page. However when I click on the browser's back button or on the 'Customers' tab then the criterion added and the search results disappear.
I have tried using the ResponseCache attribute to retain the search results but I could not make it work. I have also tried using the Cache Tag Helper but again was not successful. Anyone can help?
CustomersController
public class CustomersController : Controller
{
private readonly DbContext _context;
public CustomersController(DbContext context)
{
_context= context;
}
public IActionResult Index()
{
return View();
}
public IActionResult DisplayCustomerIdList(string searchText)
{
List<CustomerDetailViewModel> customers = _context.GetAll().ToList();
CustomerIndexViewModel model = new CustomerIndexViewModel()
{
Customers = customers
};
return PartialView("_CustomerIdListView", model);
}
public IActionResult Detail(decimal? Id)
{
Customer customer = _context.GetCustomerById(Id);
CustomerDetailViewModel model = new CustomerDetailViewModel(customer);
return View(model);
}
}
Index.cshtml
#{
ViewData["Title"] = "Customers Page";
}
#section Scripts {
<script type="text/javascript" src="~/lib/jquery/dist/jquery.min.js"></script>
<script>
var url = '#Url.Action("DisplayCustomerIdList", "Customers")';
$('#search').click(function () {
var keyWord = $('#NumberOfDays').val();
$('#searchResults').load(url, { searchText: keyWord });
return false;
})
</script>
}
<body>
<div class="input-group mb-3 w-50">
<input type="text" class="form-control mr-2" placeholder="Number of days" autocomplete="off" id="NumberOfDays">
<button id="search" class="btn btn-outline-info mb-2">Search</button>
</div>
<div id="searchResults"></div>
</body>
_CustomerIdListView.cshtml
#model MyProject.Models.CustomerIndexViewModel
<div class="card border-info mb-3 shadow" style="width:220px; height: 625px; overflow-y: scroll;">
<div class="card-header">Customer Ids</div>
<div class="list-group">
#foreach (CustomerDetailViewModel customerdetails in Model.Customers)
{
<a asp-controller="Customers" asp-action="Detail" asp-route-id="#customerdetails.CustomerId" class="list-group-item list-group-item-action">
#customerdetails.CustomerId
</a>
}
</div>
</div>
Detail.cshtml
#model MyProject.Models.CustomerDetailViewModel
<h3>Customer Information</h3>
<ul>
<li>#Model.CustomerId</li>
<li>#Model.FullName</li>
</ul>
Do the search via a GET request (rather than post). That way, the actual URL the user is sent to includes the query.
<form action="/foo" method="get">
I have figured out why this was not working and thought to add it here in case someone else has the same issue.
It turns out that the jQuery .load() method creates a POST request when the input parameter is an object (and a GET request when it is a String). So, because the ResponseCache attribute does not work with POST requests, the caching was not working.
I am using ASP.NET MVC, I have finished my project and I copied the .sln solution files to the server.
When I run it on the server, everything ok, but there is showing exceptions for the Popup forms.
I have this controller
-- The Get method
public ActionResult Remove(int id)
{
Person Person_to_remove = new Person() { Person_Id = id };
return View(Person);
}
-- The Post method
[ActionName("Remove"), HttpPost]
public ActionResult Remove_post(int id)
{
DB.Remove(id);
return RedirectToAction("Index");
}
And these views:
Index View
<table>
<tr>
<th>Name</th>
<th>Remove?</th>
</tr>
#foreach (var row in Model)
{
<tr>
<td>#row.Name</td>
<td>
Remove
<script type="text/javascript">
function Open() {
window.open('#Url.Action("Remove", new { id = row.Id })', 'popup', 'width=450,height=250');
return false;
}
</script>
</td>
</tr>
}
</table>
Remove View (As a popup window)
#using (Html.BeginForm())
{
<main>
<div>
<h3>Confirm removing:</h3>
<h1>#Model.Name</h1>
<br />
<div class="row">
<div>
<button type="submit" onclick="updateParent();">Confirm</button>
<a onclick="window.close()">Cancel</a>
</div>
</div>
</div>
</main>
}
The Index view use a default "Layout" layout and the Remove view use a "Popup" layout on the shared folder
This is the updateParent() script running on the "Popup" layout
<script type="text/javascript">
function updateParent() {
window.opener.location.reload();
window.close();
}
</script>
On my computer the app works fine, but when running on the server the popup views won't post the form, they just close without updating the data.
But when using the same URL from the Popup window into a new tab, it works. but is not desired behaviour.
I don't know what is going on, i only changed the IP in the connection string.
The problem was that the form was closing before submitting. Thanks to derloopkat for the tip.
To solve this I change Razor #Html.BeginForm() to name the form "PopUp".
Html.BeginForm(null, null, FormMethod.Post, new { name = "PopUp", id = "PopUp" })
then modify the updateParent method, to submit the form.
<script type="text/javascript">
function updateParent() {
document.forms["PopUp"].submit(); <-- Added
window.opener.location.reload();
window.close();
}
</script>
Don't know if it's the best way, but it works.
I am loading a big excel file to the database. I want my users to see that there is an activity going on. I started but didn't know how to proceed.
My ActionResult Index method has two parameters. How do I define this in my javascript.
On the click of the submit button I want the animated image to show and then stop when processing is complete
I understand I have to hide the div somehow. Not sure how to do this.
Please assist. Here is my code below.
#model SampleTemplate.Models.ResultViewModel
#{
ViewBag.Title = "Index";
}
<h2>File upload section</h2>
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="uploadSection">
<div id="divloading">
<p style="position:absolute; top:30%; left:45%;color: Red;">
Excel file in process, please wait...<img src="../../Images/animated.gif" />
</p>
</div>
<div>
<p class="headerSection">Select script</p>
<p>
<select name = "genericId">
<option value="12.1">12_1_flat_goods</option>
<option value="12.2">12_2_mats_bm</option>
</select>
</p>
</div>
<div id="spacebetween">
<p class="headerSection">Path to source file: </p>
<p class="spacebelow"><input type="file" name="file" value="" /> </p>
<p><button id="submi" name="Submit" onclick="JavascriptFunction();">Submit</button></p>
</div>
</div>
}
<script type="text/javascript" language="javascript">
function JavascriptFunction() {
var url = '#Url.Action("","Home")';
$("#divLoading").show();
}
</script>
...Here is my method
[HttpPost]
public ActionResult Index(HttpPostedFileBase file, ResultViewModel resModel)
{
//code to upload excel file goes here. No need to show this.
}
I have used Knockout.js for this before, and found it to be really clean and simple.
Check it out here: http://knockoutjs.com/
Your page would look something like this:
Knockout ViewModel javascript file -
function TestViewModel() {
var self = this;
self.itemsToDisplay = ko.observableArray([]);
//this property can be used to hold the bool for when you first hit the upload button
self.uploadStarted = ko.observable(false); // when page is loaded, this is false
//this is a property that will hold the bool value to show/hide the gif after the upload has started
self.uploadCompleted = ko.observable(false); // when page is loaded this is false
ko.applyBindings(self);
};
Then back in your View -
(Note: You will need to reference the knockout.js script in your View)
<div data-bind="visible: !uploadCompleted() && uploadStarted()">
// your gif image reference will go here
// it will only be displayed when uploadCompleted is false and uploadStarted is true
</div>
<button type="button" id="uploadButton" name="Submit">Upload</button>
<script type="text/javascript">
var viewModel = new TestViewModel();
// make an ajax call to your controller method to upload your content
// on success set your loaded property to true to hide your gif
$('#uploadButton').click(function() {
viewModel.uploadStarted(true);
$j.ajax({
type: "POST",
url: "../home/Index",
data: ko.toJSON({ file: file, resModel: model}),
contentType: "application/json",
success: function (data) {
// your controller will return your values in data
// update your viewModel properties
viewModel.itemsToDisplay(data);
viewModel.uploadCompleted(true);
viewModel.uploadStarted(false);
}
});
});
</script>
Hope that helps.
Best of luck!
I'm not sure if this can be done as the Url.Action() is trying to access a variable that's only in the foreach's scope - maybe using jQuery?
I have a strongly typed partial view that takes a view model that contains a list of search results.
I iterate through the list and each result is displayed in summarised form. Beside each item in the list there's a button that (should) when clicked launches a modal window that displays more detailed information about the list item. So if there's 10 items in the list there's going to be 10 correspdonding 'More info' buttons.
Partial View:
<div>
#foreach (var result in Model.SearchResults)
{
<div class="basic-search-result">
<div class="row-fluid">
<img class="span3" src="http://some-img.jpg" />
<div class="span3">
<div class="address">
#result.Address.TownCity<br />#result.Address.County
</div>
<div>
€#result.MonthlyRate Monthly
</div>
</div>
<div class="span3 offset1" id="basic-search-result-btns">
<button class="btn btn-primary btn-block" id="btn-show-modal-from-get-all">More info</button>
</div>
</div>
</div>
}
</div>
Just below the foreach loop I define the modal (ViewProperty is a controller action that returns a partial that contains the modal's body):
<div class="modal hide fade in" id="modal-view-property-from-get-all"
data-url="#Url.Action("ViewProperty", "ResidentialProperties", new { id = result.ResidentialPropertyId })">
<div id="view-property-from-get-all-container"></div>
</div>
When one of the buttons is clicked, it should launch a modal. Handled like this:
<script type="text/javascript">
$(document).ready(function () {
$('#btn-show-modal-from-get-all').click(function () {
var url = $('#modal-view-property-from-get-all').data('url');
$.get(url, function (data) {
$('#view-property-from-get-all-container').html(data);
$('#modal-view-property-from-get-all').modal('show');
});
});
});
I know that the Id I'm binding in the Url.Action() is outside of the scope of the foreach. Is it possible to somehow get the result.ResidentialPropertyId and pass it to the Url.Action() dynamically when a button is clicked?
To prove it's working, I placed the Url.Action() in the foreach loop, but this only launched a modal for the first item in the list. Can what I'm trying to do be achieved?
Do not include the Id in the data-url
<div class="modal hide fade in" id="modal-view-property-from-get-all"
data-url="#Url.Action("ViewProperty", "ResidentialProperties")">
<div id="view-property-from-get-all-container"></div>
</div>
With that code the data-url will have a value ResidentialProperties/ViewProperty.
Then include the Id on each row to your button or you can read it from it's container element. I also suggest you remove the id of the button and maybe just have a class to ensure that the ajax call won't get executed for all instances of your buttons
// assuming Id is the identifier per row
<button class="btn btn-primary btn-block show-modal"
data-id="#result.Id">More info</button>
and in your js do the following
$(document).ready(function () {
$('.show-modal').click(function () {
var url = $("#modal-view-property-from-get-all").attr('data-url');
var id = $(this).attr('data-id');
$.get(url + '/' + id, function (data) {
$('#view-property-from-get-all-container').html(data);
$('#modal-view-property-from-get-all').modal('show');
});
});
});
guys.
I have a View on my ASP.NET MVC Project.
This View has a lot of fields and a script to search some data.
<link href="#Url.Content("~/Content/styles/people.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/people.js")" type="text/javascript"></script>
<input type="hidden" id="selectiveAccess" name="selectiveAccess" value="#ViewBag.SelectiveAccess" />
<input type="hidden" id="peopleID" name="peopleID" value="#ViewBag.PeopleID" />
<div id="content">
<h1>People - Create</h1>
<h3>All the fields with (*) are required.</h3>
#using (Html.BeginForm("Save", "People", FormMethod.Post))
{
#Html.Partial("EnabledCourses")
#Html.Partial("GeneralData")
#Html.Partial("AddressData")
#Html.Partial("ContactData")
#Html.Partial("OtherInformations")
#Html.Partial("Research")
Back to the top
<div id="divErrors"></div>
<div id="actions">
<ul style="list-style: none;">
<li style="display: inline"><input type="reset" id="clear" style="height: 3em; width: 10em" value="Clear form" /></li>
<li style="display: inline"><input type="submit" id="continue" style="height: 3em; width: 10em" value="Continue" /></li>
</ul>
</div>
}
When I call Index(), the script works fine.
public ActionResult Index()
{
ViewBag.PeopleID = string.Empty;
return View();
}
When I call Edit(), the same script doensn't works.
public ActionResult Edit(long peopleID)
{
ViewBag.PeopleID = peopleID;
return View("Index");
}
This is the script:
function searchCityByPostalCode() {
var postalCode = {
'postalCode': $('#postalCode').val()
};
$.get(
'people/SearchCityByPostalCode',
postalCode,
function (city) {
// do something that works.
}
);
}
Anyone knows the problem?
Thanks!!!
Most likely is is due to the relative link you are using.
Index allows you to do something like this
www.mysite.com/Mycontroller/ - Goes to Index
www.mysite.com/Mycontroller/Index - Goes to Index (same as above)
However edit would force you to use the second form since there is no default route value
www.mysite.com/Mycontroller/Edit/{id}
Meaning that when you call the function for get in the index the request looks like
www.mysite.com/Mycontroller/people/SearchCityByPostalCode
And edit looks like this which is a diffrent path
www.mysite.com/Mycontroller/Edit/people/SearchCityByPostalCode
So basically you need to use an absolute reference so that the URL will work from the root of the site.
$.get(
'/people/SearchCityByPostalCode',
postalCode,
function (city) {
// do something that works.
}
);