OK, typical problem:
I have a table with 7884 of records (for now—but there will be lots...)
I want to offer admins a quick way to monitor this table through the web.
I also need to provide viewers the ability to specify some filtering to further narrow the results, as well as be able to say how many records to pull from the DB.
I'm making my intro to ASP.NET web development and so I chose to use the (more straightforward) ASP.NET WebPages framework.
I'm using the System.Web.Helpers.WebGrid to display the records and I like the fact that it automatically implements paging.
I'm using a <form method="post"> to gather the filtering parameters, so that when the form posted back, I can adjust my querying based on these values. I also assign these values to the form fields so that the user can see the posted parameters in use.
However, I noticed that the page links generated by the WebGrid that are displayed in the page footer all the reference current page URL with a query fragment of the form ?page=n.
So, obviously, when the pages are navigated, I receive a request without my page form data...
What would be your recommended pattern to solved this simple issue and keeping the development of these pages short for the time being?
#{
Layout = "~/_TablePageLayout.cshtml";
Page.Title = "Wala-Wala";
var headlinePattern = Request.Form["headlinePattern"];
var _headlinePattern = headlinePattern;
if (string.IsNullOrWhiteSpace(headlinePattern)) {
_headlinePattern = "%";
headlinePattern = string.Empty;
}
var maxCount = Request.Form["maxCount"];
int? _maxCount = maxCount.TryConvert<int>();
if (_maxCount == null || _maxCount < 0) {
_maxCount = null;
maxCount = string.Empty;
}
var database = Database.Open("Wala-Wala-DB");
var query = _maxCount == null
? #"SELECT * FROM dbo.WalaWala WHERE Headline LIKE #1"
: #"SELECT TOP(#0) * FROM dbo.WalaWala WHERE Headline LIKE #1";
var dataSource = database.Query(query, _maxCount, _headlinePattern);
var grid = new WebGrid(source: dataSource, rowsPerPage: 25, canPage: true);
grid.SortColumn = "Id";
grid.SortDirection = SortDirection.Descending;
var rowStart = grid.PageIndex * #grid.RowsPerPage + 1;
var rowEnd = grid.PageIndex * #grid.RowsPerPage + grid.Rows.Count;
}
<h1>#Page.Title</h1>
<form method="post">
<fieldset>
<legend>Search</legend>
<ol>
<li>
<label for="maxCount">Maximum:</label>
<input type="text" id="maxCount" name="maxCount" value="#maxCount""/>
</li>
<li>
<label for="headlinePattern">Headline Pattern:</label>
<input type="text" id="headlinePattern" name="headlinePattern" value="#headlinePattern""/>
<input type="submit" value="Search" />
</li>
</ol>
</fieldset>
</form>
<p>
<b>#grid.TotalRowCount entries found. Showing results #rowStart to #rowEnd (page #(grid.PageIndex + 1)
of #grid.PageCount).</b>
</p>
<div>
#grid.GetHtml(
tableStyle: "tableStyle",
alternatingRowStyle: "alternatingRowStyle",
mode: WebGridPagerModes.All,
columns: new[] {
grid.Column(columnName: "Id", style: "columnStyle"),
grid.Column(columnName: "Headline", style: "columnStyle"),
grid.Column(columnName: "DTS", style: "columnStyle"),
}
)
</div>
Use jQuery to force the form to be POSTed and prevent the click on the link from initiating a GET request. This article explains how to do that in more detail: http://www.mikesdotnetting.com/Article/180/Displaying-Search-Results-In-A-WebGrid
Related
So i got a page that have a search form, and when the user search for a value if there are no records on database the form returns empty, but if there are records the form is populated with data.
What i was thinking was this
var db = Database.Open("myDataBase");
var selectCommand = "SELECT * FROM exportClient";
var searchTerm = "";
if(!Request.QueryString["searchField"].IsEmpty() ) {
selectCommand = "SELECT * FROM exportClient WHERE clientAccount = #0";
searchTerm = Request.QueryString["searchField"];
}
if(IsPost){
var selectedData = db.Query(selectCommand, searchTerm);
}
And Then:
<body>
<div class="col_12">
<form method="get">
<label>search</label><input type="text" class="col_3" name="searchField" />
<button type="submit" class="button red" value="search">search</button>
</form>
</div>
#if(!Request.QueryString["searchField"].IsEmpty() ){
foreach(var row in db.Query(selectCommand, searchTerm)) {
<div class="col_12 box">
<form method="post">
// HERE IS THE FORM POPULATED
</form>
</div>
}
} else {
<div class="col_12 box">
<form method="post">
// HERE IS THE FORM NOT POPULATED
</form>
</div>
}
</body>
But what is happening is that the form that is not populated is always showing up when i enter the page, and i need that the only thing that user see when enter the page is the input field to do the search.
What am i doing wrong ?
I'm not sure of having understood your goal, but in my opinion your main problem is to detect if either exists or not a query string.
I think that your code should be like this
#if(Request.QueryString.HasKeys())
{
if(!Request.QueryString["searchField"].IsEmpty() ){
<p>searchField has value</p>
} else {
<p>searchField hasn't value</p>
}
}
There are a number of potential issues I can see with your code, hopefully you can put these together to achieve what you wanted:
As Selva points out, you are missing the action attribute on your forms.
The selectedData variable you create inside your IsPost() block goes out of scope before you do anything with it. Perhaps you didn't include all your code though, so ignore this if it just isn't relevant to the question.
To answer the main question: if you don't want the empty form to appear when the user hasn't yet performed a search, surely you just need to completely remove the else block - including the empty form - from your HTML?
Hope that helps.
im using spring mvc framework with thymeleaf template engine
the problem is , i have 1 page with multiple check box iterated sing thymeleaf th:each iterator.When i clicked multiple check boxes i want to pass check box values to the controller method..
html content
<table>
<tr th:each="q : ${questions}">
<h3 th:text="${q.questionPattern.questionPattern}"></h3>
<div>
<p >
<input type="checkbox" class="ads_Checkbox" th:text="${q.questionName}" th:value="${q.id}" name="id"/>
</p>
</div>
</tr>
</table>
*Controller*
#RequestMapping(value = Array("/saveAssessment"), params = Array({ "save" }))
def save(#RequestParam set: String, id:Long): String = {
var userAccount: UserAccount = secService.getLoggedUserAccount
println(userAccount)
var questionSetQuestion:QuestionSetQuestion=new QuestionSetQuestion
var questionSet: QuestionSet = new QuestionSet
questionSet.setUser(userAccount)
questionSet.setSetName(set)
questionSet.setCreatedDate(new java.sql.Date(new java.util.Date().getTime))
questionSetService.addQuestionSet(questionSet)
var list2: List[Question] = questionService.findAllQuestion
var limit=list2.size
var qustn:Question=null
var a = 1;
for( a <- 1 to limit ){
println( a );
qustn= questionService.findQuestionById(a)
questionSetQuestion.setQuestion(qustn)
questionSetQuestion.setQuestionSet(questionSet)
questionSetQuestion.setCreatedDate(new java.sql.Date(new java.util.Date().getTime))
questionSetQuestionService.addQuestionSetQuestion(questionSetQuestion) } "redirect:/teacher/Assessment.html" }
I think you pretty much have it. With a checkbox, you can only send one piece of information back with the form...that being the value. So if you are trying to determine which checkboxes are checked when the user clicks the submit button, then I would have the checkboxes all use one name...like "id" (exactly like you have). Value is the actual id of the question (again like you have). Once submitted, "id" will be a String array which includes all the values of the checkboxes that were checked.
So your controller method needs to take param called "ids" mapped to parameter "id" which is a string[]. Now for each id, you can call questionService.findQuestionById.
(I'm not a Groovy guru so no code example sry :)
I have used JSTL with JSP and thymeleaf was something new. I read the THYMELEAF documentation.
There is a section which explains multi valued check boxes.
<input type="checkbox"
class="ads_Checkbox"
th:text="${q.questionName}"
th:value="${q.id}" name="id"/>
In the above code we are not binding the value to the field of the command object. Instead try doing this
<input type="checkbox"
class="ads_Checkbox"
th:text="${q.questionName}"
th:field="*{selectedQuestions}"
th:value="${q.id}" />
here the selectedQuestions is an array object present in the spring command object.
I am aware of the previous two questions which talk about nesting partial views but the solutions don't work for my design (which might not be the best one but I'm unsure how to adapt it).
Background:
I collect questionnaire responses from users and store them on an sql server as xml files.
I have a partial view which loads a table with all the Responses of a given user, this partialview populates the table with things like Response date, link to xml response document, questionnaire name, link to xml questionnaire document (the questionnaire info is pulled from a different table) and an Ajax ActionLink which redirects to action which parses the two relevant xml documents to print out Question and Answer list (i.e. visualise the response to be human readable) inside the second partial view.
The first partial view contains a div underneath the table which I wish to populate onclick of the Ajax.ActionLink with the second partial view.
Problem:
The answers are rendered correctly however the partial view is loaded into a whole new page, without any styling.
The other solutions to this nesting problem use RenderPartial() however I use return PartialView()
Code:
First Partial View:
<table>
<thead>
<tr><th>headers with other info</th>
<th>Display(/th>
<tr>
</thead>
<tbody>
<tr><td>cells with other info</td>
<td>#Ajax.ActionLink("View", "DisplayResponse","HealthStatus", new { respID = item.UniqueID,qVersion=item.QuestionnaireVersion, qname = item.QuestionnaireName }, new AjaxOptions { UpdateTargetId = "responseDisp" })</td>
</tbody>
</table>
<div id="responseDisp"></div> <--- **This is the div I wish to populate, does anyone know why it's not working?**
DisplayResponse Action (without the logic for parsing the xml documents)
public ActionResult DisplayResponse(Guid respID, int qVersion, String qname) {
var allResponses = ZData.Responses;
var response = (from r in allResponses
where r.UniqueID == respID
select r
).First();
//geting an XML questionnaire document
var questionnaireDetails = ZodiacData.Questionnaires;
var questionnaire = (from q in questionnaireDetails
where q.Name == qname && q.Version == qVersion
select q
).First();
//creating XMLDocument to read the questionnaire
XmlDocument xqdoc = new XmlDocument();
xqdoc.LoadXml(questionnaire.Xml);
XmlElement qroot = xqdoc.DocumentElement;
ViewBag.qroot = qroot;
XmlDocument xrdoc = new XmlDocument();
xrdoc.LoadXml(response.Raw);
XmlElement rroot = xrdoc.DocumentElement;
ViewBag.rroot = rroot;
return PartialView("_PrintedResponse");
}
I would be grateful for any help!
In MVC3 the #AJax. helpers are rendering regular form and a tags with some extra data- attributes. To make the magic work some Javascript is needed which will use this generated data- attributes to make the necessary jQuery ajax calls.
These js functions are living in the jquery.unobtrusive-ajax.js so add this line to your layout or view and it should work:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")"
type="text/javascript"></script>
First, as mentioned above, you must have a reference to the jquery.unobtrusive-ajax.js file as this will get things "wired" up correctly for you.
This answer is also in response to your comment on your question about how you're passing your models to your views. You are actually making things more complicated for yourself by using the ViewBag for your model.
By using the ViewBag for your models, you will have a harder time finding/fixing/resolving issues in typo's as well as the great features of the Razor helpers. The ViewBag is a dynamic object and there are no compile time type checks. You don't need to cast your objects either (less code).
The preferred (and best practice) is to hook things up like so:
1) Your controller contains ViewModels (Strongly Typed) that are passed to the ViewModels
Controller
public ActionResult Something() {
return View();
}
public ActionResult UserView() {
UserViewModel mdoel = new UserViewModel {
Email = "me#somewherecool.com",
FirstName = "Your",
SStatuses = new List<SStatus>{
new SStatus {
ID = 0
}
}
};
return PartialView("_SomethingPartial", mdoel);
}
Index ("Something" view)
#{
ViewBag.Title = "Something";
}
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
<h2>Something</h2>
#Ajax.ActionLink("Ajax Click", "UserView", new AjaxOptions { UpdateTargetId = "MyDivContainer", InsertionMode = InsertionMode.Replace })
<div id="MyDivContainer">
<!-- my content should be here -->
</div>
Partial View
#model StackModels.UserViewModel
<div class="par">
#Html.LabelFor(m => m.FirstName)
<div class="field">
#Html.TextBoxFor(m => m.FirstName)
#Html.ValidationMessageFor(m => m.FirstName)
</div>
</div>
I'm seeking to display my images with a short title in a flow from left to right as opposed to the gridview that is a sequential layout. I desire to use the pagination that the webgrid provides so as not to recreate the wheel, as it were.
I've reviewed Leek's blog post (http://msdn.microsoft.com/en-gb/magazine/hh288075.aspx) and Broer's (http://blog.bekijkhet.com/2011/03/mvc3-webgrid-html-helper-paging.html) to ensure I have a solid introduction to the use of the webgrid but I'm falling short on how to apply the pagination without using the traditional layout of the webgrid.
I am using the Razor layouts.
Ideas or thoughts?
My controller is currently:
public ActionResult Index(string cid)
{
Catalog item = new Catalog();
item.objConnection.Open();
OdbcDataReader reader = item.getCatalogItems(cid, 3);
List<Catalog> listItems = new List<Catalog>();
while (reader.Read())
{
Catalog i = new Catalog();
i.kitName = reader.GetValue(1).ToString();
i.catalogID = reader.GetValue(0).ToString();
ViewBag.CatalogName = reader.GetValue(0).ToString(); //TODO: change this to name once in place
listItems.Add(i);
}
ViewBag.ItemsPerCatagory = listItems.Count;
reader.Close();
item.objConnection.Close();
return View(listItems);
}
My View:
#model IEnumerable<MvcApplication1.Models.Catalog>
#{
ViewBag.Title = ViewBag.CatalogName;
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>#ViewBag.CatalogName (#ViewBag.ItemsPerCatagory) Items Available</h2>
<p>
Category will have a brief description here for seo purposes.
</p>
<p>
#foreach (var catalog in Model)
{
string imageUrl = "http://web3.naeir.org/images/Specials/" + #catalog.kitName + ".JPG";
<img src=#imageUrl height="150px" width="150px" /> #Html.ActionLink(#catalog.kitName, "Details", "Product", new { cid = #catalog.catalogID, itemid = #catalog.kitName }, null)
}
</p>
Upon much hacking at my code I found that a simple option exist and my solution was to use MVCPager MVC Pager Website
I was able to simply download it via VS Web Developer Express Package Manager NuGet, read the documentation and implemented the code. Pretty straight forward.
I am trying to create a situation where if a user clicks on an "edit" button in a list of text items, she can edit that item. I am trying to make the "edit" button post back using ajax.
Here's my ajax code:
$(function () {
// post back edit request
$('input[name^="editItem"]').live("click", (function () {
var id = $(this).attr('id');
var sections = id.split('_');
if (sections.length == 2) {
var itemID = sections[1];
var divID = "message_" + itemID;
var form = $("#newsForm");
$.post(
form.attr("action"),
form.serialize(),
function (data) {
$("#" + divID).html(data);
}
);
}
return false;
}));
});
But the form.serialize() command is not picking up all the form controls in the form. It's ONLY picking up a hidden form field that appears for each item in the list.
Here's the code in the view, inside a loop that displays all the items:
**** this is the only control being picked up: ******
#Html.Hidden(indexItemID, j.ToString())
****
<div class="datetext" style="float: right; margin-bottom: 5px;">
#Model.newsItems[j].datePosted.Value.ToLongDateString()
</div>
#if (Model.newsItems[j].showEdit)
{
// *********** show the editor ************
<div id="#divID">
#Html.EditorFor(model => model.newsItems[j])
</div>
}
else
{
// *********** show the normal display, plus the following edit/delete buttons ***********
if (Model.newsItems[j].canEdit)
{
string editID = "editItem_" + Model.newsItems[j].itemID.ToString();
string deleteID = "deleteItem_" + Model.newsItems[j].itemID.ToString();
<div class="buttonblock">
<div style="float: right">
<input id="#editID" name="#editID" type="submit" class="smallsubmittext cancel" title="edit this item" value="Edit" />
</div>
<div style="float: right">
<input id="#deleteID" name="#deleteID" type="submit" class="smallsubmittext cancel" title="delete this item" value="Delete" />
</div>
</div>
<div class="clear"></div>
}
It's not picking up anything but the series of hidden form fields (indexItemID). Why would it not be picking up the button controls?
(The ID's of the edit button controls, by the way, are in the form "editItem_x" where x is the ID of the item. Thus the button controls are central to the whole process -- that's how I figure out which item the user wants to edit.)
UPDATE
The answer seems to be in the jquery API itself, http://api.jquery.com/serialize/:
"No submit button value is serialized since the form was not submitted using a button."
I don't know how my action is supposed to know which button was clicked, so I am manually adding the button to the serialized string, and it does seem to work, as inelegant as it seems.
UPDATE 2
I spoke too soon -- the ajax is not working to update my partial view. It's giving me an exception because one of the sections in my layout page is undefined. I give up -- I can't waste any more time on this. No Ajax for this project.
You could try:
var form = $('#newsForm *'); // note the '*'
Update
Did you change the argument to $.post() as well? I think I may have been a little too simple in my answer. Just change the second argument within $.post() while continuing to use form.attr('action')
New post should look like this:
$.post(
form.attr("action"),
$('#newsForm *').serialize(), // this line changed
function (data) {
$("#" + divID).html(data);
}
);