Multiple pages, single controller, how to set it up in mvc? - asp.net-mvc

I have a 'home' controller which deals with the basic Home, About, Courses, Contact pages. There are multiple courses available, each with their own page and I would like to know the best method for referencing these pages. I could just create them as additional pages and add an actionresult to the home controller for each page. So the url for a course would be home/course1. Presumably there is a much better method than this though.
Ideally I'd like to have the individual course pages in a separate folder within the view folder and their url to be /home/courses/course1. Can anyone explain the best method using MVC for organising these pages?

So it goes like this : There will be a single page for all the courses and all the course pages will be partial views now there will be a div on the main page and whenever user clicks one of the course name.. it will fire an ajax request and it returns the required partial and populate the div with the returned content. You can give a common class to all the links of Courses, just like this :
.<a class="couseTrigger" data-source="#Url.Action("Name of Partialview action,"
name of controller")">
------ Script -----
$('.couseTrigger').click(function(){
var _this = $(this);
var url = _this.data('source');
--then make the ajax request to this url pvariable and retrun the partial view.
});

If you have multiple courser avoid creating multiple webpages for those courses. Rather have the content of each course stored in a database and retrieve specific course content by some parameter and bind it to the webpage. Creating webpage for each course is not feasible. Suppose you have 100 courses are u gonna create 100 webpages ?

Related

Passing and Storing objects between Pages

I'd like some advice on this issue. Basically, I have 2 pages (for simplicity sake), and the second page is completely dependent on the first page.
So lets say the main page is a search page, and the second page is a view page.
The site works off XML requests, and the ultimate aim is to keep the XML requests to a minimum as each request is a little slow. I considered using Sessions, but I've had some problems in the past with sessions being mixed between users randomly which i only manage to curb by changing the recycle process in IIS to a very small time frame, so I'm wondering if there is any other way. I've tried TempData, but that expires after one request, so a page refresh on the view page doesn't seem possible. (or is it?)
Anyways, we have the Search page that has, say, 5 attributes that are required by the View page, but only 2 are needed to make the XML request on the view page.
e.g.
Search Page Contains:
ID,
Name,
City,
Email,
Height
View Page needs the following from the Search page to complete the xml request:
ID,
Name,
Email
View Page displays all the information from the search page, plus everything in the XML response.
The link i have in the search page only has the ID in the url, so name and email are required for the XML request on the second page some how. Not sure if it's possible without sessions?
What i've tried is:
Store the search results in TempData. That way, when someone clicks the 'View' link (View), the View page loads the search results like so:
var viewPage = SearchResults.Where(w => w.ID == id).FirstOrDefault();
The ViewModel then renders the page by grabbing the Name and Email from viewPage, making an XML request, and displaying the response, along with other required details from viewPage.
It works as expected with tempdata. Data only persists on the first request, dies on a page refresh. Sessions is the alternative, but is there any other?
(sorry for the wall of text :)
Why not using more standard techniques like a <form> tag in the search page pointing to the controller action that will perform the search:
#using (Html.BeginForm("search", "somecontroller", FormMethod.Get))
{
... some input fields for your search criteria
<button type="submit">Search</button>
}
and then you will have the Search controller action:
public ActionResult Search(SearchModel model)
{
var results = ....
return View(results);
}
I've used GET method on the form which allows the user to bookmark the results page and come back to it later.

ASP.NET MVC - Complicated view logic

I'm making the transition from webforms to MVC (I know, 3 years late) and I "get it" for the most part, but there's a few things I'd like advice and clarification on:
First off, what happens if you want to dynamically add inputs to a view? for example, in an old webform for generating invoices I had a button with a server-side click event handler that added an extra 5 invoice item rows. The stateful nature of webforms meant the server handled the POST event "safely" without altering the rest of the page.
In MVC I can't think how I'd do this without using client-side scripting (not a showstopper, but I would like to support clients that don't have scripting enabled).
The second problem relates to the invoices example. If my Model has a List, how should I be generating inputs for it?
I know data binding is a possible solution, but I dint like surrendering control.
Finally, back to the "stateful pages" concept - say I've got a Dashboard page that has a calendar on it (I wrote my own calendar Control class, the control itself is stateless, but can use the webform viewstate to store paging information) - how could a user page through the calendar months? Obviously POST is inappropriate, so it would have to be with GET with a querystring parameter - how can I do this in MVC? (don't say AJAX).
Thanks!
In MVC you design your actions to accommodate your needs. For example, if you wanted to be able to add 5 rows to an invoice NOT using client-side scripting, you'd probably have your GET action for the invoice generation take a nullable int parameter for the number of rows. Store the current number of rows in the view model for the page and generate a link on the page to your GET action that has the parameter value set to 5 more than the current value. The user clicks the link and the GET view generates the page with the requested number of rows.
Controller
[HttpGet]
public ActionResult Invoice( int? rows )
{
rows = rows ?? 5; // probably you'd pull the default from a configuration
...
viewModel.CurrentRows = rows;
return View( viewModel );
}
View
#Html.ActionLink( "Add 5 Lines", "invoice", new { rows = Model.CurrentRows + 5 }, new { #class = "add-rows" } )
You would probably also add some script to the page that intercepts the click handler and does the same thing via the script that your action would do so that in the general case the user doesn't have to do a round trip to the server.
<script type="text/javascript">
$(function() {
$('.add-rows').click( function() {
...add additional inputs to the invoice...
return false; // abort the request
});
});
</script>
Likewise for your calendar. The general idea is you put enough information in your view model to generate all the actions that you want to perform from your view. Construct the links or forms (yes you can have multiple forms!) in your view to do the action. Use parameters to communicate to the controller/action what needs to be done. In the rare case where you need to retain state between actions, say when performing a wizard that takes multiple actions, you can store the information in the session or use TempData (which uses the session).
For things like a calendar you'd need the current date and the current view type (month/day/year). From that you can construct an action that takes you to the next month/day/year. For a paged list you need the current page, the current sort column and direction, the number of items per page, and the number of pages. Using this information you can construct your paging links that call back to actions expecting those parameters which simply do the right thing for the parameters with which they are called.
Lastly, don't fear AJAX, embrace it. It's not always appropriate (you can't upload files with it, for example), but your users will appreciate an AJAX-enabled interface.
In MVC you can store application state in various ways. In your controller you have direct access to the Session object and you can also store state to the database.
your view can contain basic control flow logic, so, if your model has a list you can iterate over it in the view and, for example, render an input control for each item in the list. you could also set a variable in a model to be the maximum number of rows on the viewpage and then render a row in a table for the number specified by the model.
paging is basically the same thing. you can create a partial view (user control in the webform world) that shows page numbers as links, where each link calls an action that fetches the data for that page of results.
i'm not sure what your beef is with ajax or javascript

MVC Models for complex page

I'm working on an ASP.Net MVC project. My index page will be similar to facebook's which means that the user can write a message but also sees the messages of his/her friends and a list of his friends is shown too. That means that there are two outputs and one input.
How should my Models for this page look like? Is it a good idea to have one IndexModel containing a list of all messages (List), a list of all friends (List), and an InputMessage class?
Or should I write one Model for each of them and put them together within a ViewModel?
Thanks
Your best bet is actually to split out either the friends list, messages list or both into their own partial views. Then if you don't want to have one controller action generate data for them, you can create actions for each of them and use Html.RenderAction to show them.
http://msdn.microsoft.com/en-us/library/system.web.mvc.html.childactionextensions.renderaction.aspx
If I am correct then your webpage will have static(list of friends) as well as dynamic(list of messages) content. I would suggest you to have a strongly typed view with with your model containing all the static content including the list of friends e.g. IEnumerable.
For messages create partail view using jQuery-template feature. Define the template as on how to display the messages, bind the template with raw json data(which will basically contain your messages) and embed this partial view in you strongly typed view.
Partial views can be resused so tomorrow you can use the same view to show messages else where in application.
For more on how to design using jQuery template : https://github.com/nje/jquery-tmpl/wiki/List-of-jQuery-tmpl-articles-and-tutorials
Friends and Messages are two different concerns so they got to be in different ActionResults, no matter how you plan to display them later on (using templating or something else)

Is it i possible to prevent certain PartialViews from being served if requested directly?

I'm working on a site that has routes to actions which render Partial Views. A lot of these partial views are components which together make up a complete page.
For instance on a search page I'm working on has a text box, a list of tabs, and a Table.
Seach of these can be accessed with a URL similar to
/Search/SearchPanel
/Search/Tabs/{SearchTerm}
/Search/ResultsTable/SearchTerm?tab=[currently selected tab]
and these are all rendered on with a RenderPartial on my Index page.
When the page loads, it will display each of these components the way I want it. But at the moment there's nothing stopping a user from going directly to the url
/Search/Tabs
to render only a tab control which is meaningless outside the context of the rest of the elements on the page.
Is there a way for me to prevent this?
Have you tried marking your Controller method as private?
private PartialViewResult MyPartialResultMethod()
This should allow you to call it from within your code to build up your pages and disallow any public access such as through a URl.
I'm testing this now to make doubly sure my answer is correct so I'll update as I test.
In your tabs example you could simply restrict access by using a second controller method for Tabs that's private.
So you'd have something that looks like:
public ActionResult Tabs(string searchTerm) // When a search term is passed.
and
private ActionResult Tabs() // When no search term is passed.
You could create an ActionFilter which checks if the Request.IsAjaxRequest() is true. If it's not (meaning the user is calling the view directly), re-direct accordingly.

ASP.NET MVC Catching 'Save' POST with RenderPartial

I have a asp.net mvc page which renders a record from a database, it uses RenderPartial to call another view which renders an editable list of items related to that record.
My problem is I want a since save / submit button which not only saves changes made for that record but also changes made in the RenderPartial part... I have created a method accepting POST in the RenderPartials controller but it doesn't get called? Any ideas? Or am I using RenderPartial wrongly? I did it this way so that I have a controller that handles the subset of data
Update:
I don't think I've been clear enough:
Imagine a situation where you have a page that is filled with information from lots of different tables in a database... for example imagine you have a record of a person, and then you have all the links they have to Organisations that you want to list on the page, so the page contains:
Individual Name, Email, etc...
AND
Organisation Link 1
Organisation Link 2, etc... from a link table
Because of the amount of data I want to render of the page, I figured using different controllers to render each part would make sense.. but then when saving the data do I have to use just one controller method or can I call one controller to another... I only have one form and one 'save' button for the whole page
I hope this is clearer?
You don't need to have a specific controller for each controller, although I suspect you meant to say "I have created a method accepting POST in the RenderPartial's action ..."?
When you accept the default html helper commands, it can sometimes get confusing which action will be called. For a particular web page, the tag will determine where to POST values. So the action called will be dependent on the controller/action you specify in your Html.BeginForm call.
For example, here's a form we use from an ascx page:
<% using (Html.BeginForm("InvoiceDetail" //Action
, "CompanyInvoice" //Controller
, FormMethod.Post
, new { #id = "InvoiceForm", #autocomplete = "off" }))
{%>
A form can post to any action, in any controller. Not that you'd want to, but it's quite flexible. You can also have multiple forms in a single web page now, which is great for complex forms.

Resources