Displaying PartialView when user enters text? Like an Autocomplete feature? - asp.net

I've watch the videos on asp.net and I've looked online and have found nothing.
I have a search box on a site, that searches for recipes. Each recipe has a what you're making image, a title, and type(dessert, lunch, dinner).
All of these items are in a DataService, which I can query against and get a list of the items they are searching for.
Now I'm using VB's ASP.NET MVC3 w/ Razors for the site and I'm trying to get some auto completeness going on when the user enters text.
What should happen is when the user enter text, it will call an ActionResult in the Search Controller. Which queries the DataService and puts all the search results in a model. With that model I return a PartialView, results, with the Model included.
And it should display that partial view, but when the users deletes all the text I will remove the partial view.
Here's what I implemented. In the Layout View
#Code
Using Ajax.BeginForm("FastSearchResults", "Search", "", New AjaxOptions With {.UpdateTargetId = "searchitems", .HttpMethod = "GET", .InsertionMode = InsertionMode.Replace})
Html.BeginForm("Results", "Search", FormMethod.Get)
#<input type="text" name="id" id="searchbox" data-autocomplete="#Url.Action("FastSearchResults", "Search")" class="recipevox" value="Search Movie Title or Actor Here" />
Html.EndForm()
End Using
End Code
<span id="searchitems"></span>
The FastResult Method
Function FastSearchResults(ByVal id As String) As ActionResult
Dim model = search.FastSearch(id)
Return PartialView("_FastSearchResults", model)
End Function
Javascript Code
$(document).ready(function () {
$(":input[data-autocomplete]").autocomplete({ source: $(this).attr("data-autocomplete") }); });
I curious as to why this doesn't work, what else am I missing?

Your FastSearchResults controller action returns a partial view which presumably contains HTML. The autocomplete plugin doesn't expect HTML. It expects text or JSON. So to make this work you could have a different controller action specifically for the autocomplete:
<HttpPost()>
Function SearchResults(ByVal id As String) As ActionResult
' TODO: Query your service and return a list of model containing Id and Value properties
Dim model = Enumerable.Range(1, 10).Select(Function(x) New With {.Id = x, .Value = "item" & x})
Return Json(model)
End Function
and then setup your autocomplete:
<script src="#Url.Content("~/Scripts/jquery-1.5.1.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui-1.8.11.js")" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$(":input[data-autocomplete]").autocomplete({
source: function (request, response) {
$.ajax({
url: this.element.attr('data-autocomplete'),
type: 'POST',
data: { id: request.term },
success: function (result) {
response(
$.map(result, function (item) {
return {
// Here we must map between the server side JSON
// and the autocomplete expected format
label: item.Value,
id: item.Id
};
})
);
}
});
},
minLength: 2
});
});
</script>
As far as the other controller action which returns a partial view you could keep it and it will be executed when the form is submitted using AJAX and the results of it will be injected into the #searchitems div.

Related

Calling method from razor page

I have a asp.net core mvc project.
In my layout file, I want to display the name of the currently logged in user, such that the username is displayed in the header. For this, I want to be able to call a function in my homecontroller that does this.
So, I made a simple function taht looks like this in the home controller:
public String GetLoggedInuser()
{
return "garse garsebro";
}
And then I have tried every method I have been able to find. The first couple of methods here are just function suggested around the web, that are simply not available to me:
#HtmlHelper.Action("GetLoggedInuser");
#Html.RenderAction("GetLoggedInuser");
To name a few. Then there is this one, which I can find:
#Html.ActionLink("GetLoggedInuser")
But for this one, my function "GetLoggedInuser" can't be found anywhere.
How do you, in a razor page call a controller function that you can get returned a string from that function and display it?
If you are using Microsoft.AspNet.Identity then below line will do the work post login.
#Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
You can try to use ajax to call action to get the username,and add it to html:
<div id="username">
</div>
#section scripts
{
<script>
$(function () {
$.ajax({
type: "GET",
url: 'GetLoggedInuser',
}).done(function (result) {
$("#username").html(result);
});
})
</script>
}

#if not rendering form options on change of other form element

Within my view I have a select box. If a certain value is selected I want more form options to appear below using #if.
#model App.ViewModels.JobVM
<div class="row">
<div class="form-group">
#Html.Label("Job Type", new { #class = "control-label" })
#Html.DropDownListFor(model => model.JobId,
new SelectList(App.ViewModels.JobVM.GetJobs(),
"Value", "Text"),
"--Choose Job Type--",
new { #class = "form-control"})
</div>
</div>
...
#if (Model.JobId == 1)
{
.... more form options
}
However when running if the select option that give Job ID 1; the form options don't render.
Is there a reason why the form options do not appear when the Select option changes? Or will I have to use javascript to accomplish this goal?
It's expected behavior as view is rendered on server once before sending data to browser. However, for displaying additional inputs you can use both methods - js or partial views (even with ajax if you need) you have to use only JavaScript to show/hide other elements of form for required cases.
The #if statement and Model.JobId executed server-side, hence Model.JobId value doesn't change when the dropdown selected value has changed because change event occurred in client-side. By handling change event with JS, you can use AJAX call to set the value and display additional form options which contained inside partial view:
jQuery AJAX call
$('#JobId').change(function () {
var jobId = $(this).val();
if (jobId == 1) {
$.ajax({
type: 'GET', // or 'POST'
url: '#Url.Action("ActionName", "ControllerName")',
data: { JobId : jobId },
success: function (result) {
$('#formoptions').html(result);
},
// other stuff
});
}
else {
$('#formoptions').empty();
}
});
Controller Action
public ActionResult ActionName(int JobId)
{
// do something
return PartialView("_FormOptions", viewmodel);
}
If the form options are already rendered together inside view, instead of using server-side #if block, simply use a <div> placeholder and toggle its visibility like this:
$('#JobId').change(function () {
var jobId = $(this).val();
if (jobId == 1) {
$('#formoptions').show(); // show form options
} else {
$('#formoptions').hide(); // hide form options
}
});
HTML
<div id="formoptions">
<!-- more form options -->
</div>

KendoUI Grid Custom Toolbar Action to delete selected items

I'm trying to add a new Custom Toolbar Action to my Kendo UI Grid but am lost on how to get the desired behaviour.
I need a button that I can click that will invoke an action method and pass in the collection of selected items in the grid so I can do a bulk delete (or some other action against all of the records)
Can anyone help ?
Currently I have: -
.ToolBar(toolbar =>
{
toolbar.Custom().Action("Users_DeleteSelected", "Users").Text("Delete Selected");
})
This invokes my method thus: -
public ActionResult Users_DeleteSelected([DataSourceRequest] DataSourceRequest request)
{
// We need the list of selected UI items *here* so we can delete them - but how
...???
// Just redirect for now, we need to test getting the list of selected items here...
RedirectToAction("Index");
}
So if I have several items "selected" in the grid, I somehow want to invoke a method like the one above (Users_DeleteSelected) and have it get passed in the list of items to delete, then redirect to the Index once the delete is complete.
** This may not just be linked to deleting - there may in future be several other functions that will be required that fit the same method - i.e. "Mark As Complete" on a list of jobs for example.
I'm guessing maybe the DataSourceRequest isn't the way to go and that maybe I need to add some client side code to somehow assemble the list of selected items.
KendoUI is great but I need more examples.
Thanks for your kind replies. We've figured it out with a bit of searching and the like.
Firstly "kudos" to "this post" on the kendoui site as it pointed me in the right direction.
It turns out that this is what we need: -
In the. cshtml file for the grid...
// .... Other grid stuff
.ToolBar(toolbar =>
{
toolbar.Custom().Text("Test Button").Url("#").HtmlAttributes(new { #class = "test-button" });
})
// And then also...
$(document).ready(function () {
$(".test-button").click(testFunction)
})
// And finally
function testFunction(e) {
kendoConsole.log("Items Selected");
e.preventDefault();
var grid = $("#Grid").data("kendoGrid");
var selection = [];
grid.select().each(
function () {
var dataItem = grid.dataItem($(this));
selection.push(dataItem);
}
);
$.ajax({
type: "POST",
url: "Users/Users_DeleteSelected",
data: JSON.stringify({ items: selection }),
dataType: "html",
contentType: "application/json; charset=utf-8",
success: function (form) {
document.open();
document.write(form);
document.close();
}
});
};
Then in the controller we simply have: -
[HttpPost]
public ActionResult Users_DeleteSelected(List<UserViewModel> items)
{
// Stub to redirect for now
return RedirectToAction("Index");
}
And that's it. All of the items currently selected in the grid will be posted back to the correct action method and the jobs done.
Thanks.
Sounds like you are looking for batch editing capability. Take a look at this Kendo batch editing example. You can control whether to batch or not on the DataSource.

In ASP.NET, a POST/Redirect/GET sequence with AJAX hits the redirected-to action twice

Inside a view, I have the following:
#using (Html.BeginForm())
{
<input type="submit" id="savebtn" value="Save" onclick="saveLayout()"/>
}
<script type="text/javascript">
function saveLayout() {
$.ajax({
url: '/Page/SaveFaces/',
data: {
/* layout data of the page, irrelevant */
},
type: 'post',
success: function () {
}
});
return false;
}
</script>
The above hits the following action, which simply redirects the user back to the URL they came from (it's also supposed to save the data, but I've removed that part for simplicity, as it doesn't affect the problem):
[HttpPost]
public ActionResult SaveFaces(string items)
{
return Redirect(Request.UrlReferrer.AbsoluteUri);
}
Then, due to the redirect, we go back to this pretty standard model-fetching action:
public ActionResult Index(int id = 0)
{
var page = db.Pages.Find(id);
if (page == null) return HttpNotFound();
return View(page);
}
The problem is that this last action is called twice.
I have tried removing the AJAX call and doing a normal POST operation and the problem goes away. However, the data I'm trying to send is obtainable only through the a jQuery script and I can't put them in a form. I'm constrained to work with the AJAX method.
Is there anything I can do to prevent the action from being hit twice?
I see you are using jQuery. Can you try this instead? (Note you may have to bind the the form submit event rather than the input button, or both)
#using (Html.BeginForm())
{
<input type="submit" id="savebtn" value="Save" >
}
<script type="text/javascript">
$("#savebtn").submit(function saveLayout(event) {
// The magic that prevents post.
event.preventDefault();
$.ajax({
url: '/Page/SaveFaces/',
data: {
/* layout data of the page, irrelevant */
},
type: 'post',
success: function () {
}
});
return false;
}
</script>
Also if you have access to form element, another way:
<form onsubmit="javascript: return false;">
Though it might be a bit specific to my scenario, I just found an acceptable solution. Since all the data is provided through jQuery, I removed the form completely and replaced the submit button with a simple link.
So, this goes away:
#using (Html.BeginForm())
{
<input type="submit" id="savebtn" value="Save" />
}
And this is put in place instead:
<a onclick="saveLayout()" id="saveLink">Click to save.</a>
Now the [HttpPost] action is hit, the data is saved and the redirected-to action is also hit, once.

MVC3 Dynamic list update issue

I have a dynamic list and I need to return the selected items from view back to the controller. I have checked the link CheckboxList in MVC3 View and get the checked items passed to the controller the problem is i have a dynamic list and i need to display it horizontally so i am using
<table>
<tr>
#foreach (var item in mylist)
{
<td><img src='#item.PictureUrl'/><br />#Html.CheckBox(#item.Id,#item.checkedin)#item.Name</td>
}
</tr>
</table>
I also have a textarea in the same form.
In the controller post method, I am able to access the textarea value but not the list or checked items. please help.
Or is there any other better way to display my list and get back the checklist items?
I am new to MVC, any help would be appreciated.
Thanks
Using the JQuery is the best way:
1- Download Jquery.json.js and add it to your view:
<script src="../../Scripts/jquery.json.js" type="text/javascript"></script>
2- add a ".cssMyClass" to all checkboxes so you can grab the values by their css class:
<script type="text/javascript" >
$(document).ready(function () {
$("#btnSubmit").click(sendValues);
});
function populateValues()
{
var data = new Array();
$('.myCssClas').each(function () {
if ($(this).attr('checked')) {
var x = $(this).attr("value");
data.push(x);
}
});
return data;
}
function sendValues() {
var data = populateValues();
$.ajax({
type: 'POST',
url: '#Url.Content("~/Home/Save")',
data: $.json.encode(data),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function () { alert("1"); }
});
}
</script>
As you can see I've added all selected values to an Array and I've passed it to "Save" action of "Home" controller by ajax
*- in Controller you can receive the values by adding an array as argument:
[HttpPost]
public ActionResult Save(int[] val)
{
I've searched too much but apparently this is the only solution. Please let me know if you find a better solution for it.

Resources