Load data only when page is scrolled down MVC 4 Jquery Mobile - c#

In my view am populating contents taken from a Table which has more than 1000 records. I have to populate the contents in a manner that records are populated to fewer records only when scrolled down and not at once. I use this for developing a mobile application. I have tried with various sources online but not effective to the extent of scrolling. If you are still not clear with my question, most of you might have used facebook. There the posts are not loaded all at once. only when scrolled they are loaded. i have to implement the same functionality. Any references to the realtime code will be appreciated. thanks in advance.
Here is my code where i am getting the records
#foreach (System.Data.DataRow row in Model.dtSearch.Rows)
{
if (Model.dtSearch.Rows.Count > 0)
{
<input type ="hidden" value="#row["ProductId"]" />
<input type ="hidden" value="#row["ProductPriceId"]" />
<div class="divSearchResult" id="divSearch">
<table>
<tbody>
<tr><td rowspan="2" style="width:10%"> #Html.Raw(row["ThumbnailFilename"])</td>
<td colspan="3"><div class="divSearchHeader"> #row["ProductName"] <br /></div></td></tr>
<tr><td colspan="4"><div class="divSearchShowHide" ><a class="classShow" id="show" href="#" style="text-decoration:none">Show</a></div>
<div style="display:none;" class="divSearchContent" id=divresult_#ProductDescription > #Html.Raw(row["ProductDescription"])</div></td></tr>
</tbody>
</table>
<hr />
</div>
}}
There is no point in showing the code but this is where i must get the functionality implemented

RustyLazyLoad consists of six main components:
1.rustylazyload.js
2.rustylazyload.css
3.RustyLazyLoadViewModel.cs
4._RustyLazyLoad.cshtml
5.Your Controller lazy load action method and the corresponding ViewModel
6.Your PartialView template
First, we'll quickly run through rustylazyload.js:
function LazyLoad(uniqueId) {
var _uniqueId = uniqueId;
var _containerId = "";
var _ajaxLoadContainerId = "";
var _ajaxActionUrl = "";
var _parameters = {};
this.init = function(option) {
_containerId = option.containerId;
_ajaxLoadContainerId = option.ajaxLoadContainerId;
_ajaxActionUrl = option.ajaxActionUrl;
_parameters = option.parameters;
// Enable scroll event handler
bindScrollHandler();
// Load initial items
load();
};
var bindScrollHandler = function() {
$(window).scroll(function() {
if ($(window).scrollTop() + $(window).height() > $(document).height() - 200) {
load();
}
});
};
var unbindScrollHandler = function() {
$(window).unbind("scroll");
};
var load = function() {
$.ajax({
type: "POST",
url: _ajaxActionUrl,
data: _parameters,
beforeSend: load_beforeSend,
success: load_success,
error: load_error
});
};
var load_beforeSend = function() {
// Disable scroll event handler
unbindScrollHandler();
// Show loading message
$(_ajaxLoadContainerId).toggleClass("lazyload-hidden").html("Loading..");
};
var load_success = function(result) {
// Delay a bit before displaying the result and re-enabling scroll event handler
setTimeout(function() {
// Display result with fade in effect
if (result != null && result != "") {
$(_containerId).append(result, { duration: 500 });
// Add ui-first-child to the first child
$(_containerId).find(">:first-child").removeClass("ui-first-child");
$(_containerId).find(">:first-child").addClass("ui-first-child");
// Remove ui-last-child from the old last child
$(_containerId).find(">:nth-child(" + _parameters.fromRowNumber + ")").removeClass("ui-last-child");
// Add ui-last-child to the new last child
$(_containerId).find(">:last-child").addClass("ui-last-child");
// Update fromRowNumber
_parameters.fromRowNumber = $(_containerId).children().length;
}
if (_parameters.fromRowNumber == 0) {
// Use loading container to display 'no item' message
$(_ajaxLoadContainerId).html("There is no data to display");
} else {
// Remove loading message
$(_ajaxLoadContainerId).toggleClass("lazyload-hidden").html("");
}
// Re-enable scroll handler
bindScrollHandler();
}, 500);
};
var load_error = function(result) {
var message = result.responseText.substring(1, result.responseText.length - 2);
$(_ajaxLoadContainerId).html("Error: " + message);
};
}
There are 4 mandatory fields that we need to specify when calling init():
_containerId - the Id of the data container object (<ul id="thisId"></ul>)
_ajaxLoadContainerId - the Id of the "Loading" message container object (<div id="thisId">Loading..</div>)
_ajaxActionUrl - The action Url which will be called using $.ajax()
_parameters - a JSON object, which has 2 mandatory fields: limit (number of items to be loaded on demand) and fromRowNumber (marks the Nth loaded item to avoid repeated entries).
We won't go and discuss this code above line by line, instead we'll just highlight the important sections:
init() function does three things: maps the parameters, binds scroll event handler to the window, and calls load() to display the first batch
bindScrollHandler() is quite trivial - it simply makes sure load() gets called when the window almost reaches the bottom
load() calls _ajaxActionUrl using jQuery AJAX and passes all specified parameters in _parameters variable - ASP.NET MVC is smart enough to map those parameters with the Controller action parameters
When the Controller action is performing, load_beforeSend() temporarily disables the window scroll event handler so we don't overload the server with AJAX requests, meanwhile displays the loading message HTML object which Id is stored in _ajaxLoadContainerId
On success, load_success() should bind the result to _containerId HTML object, update the _parameters.fromRowNumber with the number of items loaded (remember fromRowNumber is one of the mandatory items of _parameters), and re-enables the window scroll event handler
Any error will be handled in load_error(), which will be displayed in _ajaxLoadContainerId HTML object
If you are using default ASP.NET MVC4 Mobile Application template, you shouldn't need to modify this file at all
Next is rustylazyload.css, which should be quite straight forward:
.lazyload-loading-container {
margin: 0;
padding: 15px;
text-align: center;
}
.lazyload-hidden {
display: none;
}
Now, the View Model RustyLazyLoadViewModel.cs:
using System.Collections.Generic;
namespace RustyLazyLoadTester.Mobile.Models
{
public class RustyLazyLoadViewModel
{
public RustyLazyLoadViewModel()
{
Parameters = new Dictionary<string, object>();
}
public RustyLazyLoadViewModel(int limit, int fromRowNumber, string containerId,
string ajaxActionUrl, IDictionary<string, object> parameters = null)
{
Limit = limit;
FromRowNumber = fromRowNumber;
ContainerId = containerId;
AjaxActionUrl = ajaxActionUrl;
if (parameters != null)
Parameters = parameters;
}
public int Limit { get; set; }
public int FromRowNumber { get; set; }
public string ContainerId { get; set; }
public string AjaxActionUrl { get; set; }
public IDictionary<string, object> Parameters { get; set; }
}
}
As you can see, this View Model captures pretty much the same parameters as rustylazyload.js' .init() function, except without the _ajaxLoadContainerId. Why? Let's check out the View file.
_RustyLazyLoad.cshtml:
#using System.Text
#model RustyLazyLoadTester.Mobile.Models.RustyLazyLoadViewModel
#{
var containerId = Model.ContainerId;
var ajaxLoadContainerId = string.Format("{0}Load", containerId);
// Convert parameters to JSON
var sbParameters = new StringBuilder();
if (Model.Parameters != null && Model.Parameters.Any())
{
foreach (var parameter in Model.Parameters)
{
sbParameters.AppendFormat("\"{0}\": \"{1}\", ", parameter.Key, parameter.Value);
}
}
var parameters = sbParameters.ToString();
// Remove trailing ', ' from parameters
if (!string.IsNullOrWhiteSpace(parameters))
{
parameters = parameters.Substring(0, parameters.Length - 2);
}
}
<ul id="#containerId" data-role="listview"
data-inset="true"></ul>
<div id="#ajaxLoadContainerId"
class="lazyload-loading-container lazyload-hidden
ui-listview ui-listview-inset
ui-corner-all ui-shadow ui-li-static
ui-btn-down-b ui-first-child ui-last-child"></div>
<script type="text/javascript">
$(document).ready(function () {
var limit = #Model.Limit;
var fromRowNumber = #Model.FromRowNumber;
var containerId = '#string.Format("#{0}", containerId)';
var ajaxLoadContainerId = '#string.Format("#{0}", ajaxLoadContainerId)';
var ajaxActionUrl = '#Model.AjaxActionUrl';
var parameters = { limit: limit, fromRowNumber: fromRowNumber, #Html.Raw(parameters) };
var lazyLoad = new LazyLoad(containerId);
lazyLoad.init({
containerId: containerId,
ajaxLoadContainerId: ajaxLoadContainerId,
ajaxActionUrl: ajaxActionUrl,
parameters: parameters
});
});
</script>
For simplicity, _ajaxLoadContainerId is really just _containerId with a suffix, but it can be anything, really. Should we feel the need to specify your AJAX loading message container Id manually, all we need to do is add AjaxLoadContainerId as a property in RustyLazyLoadViewModel.cs and pass that on to variable ajaxLoadContainerId (line 5 in this page).
The lazy load item container is this:
<ul id="#containerId" data-role="listview" data-inset="true"></ul>
And the lazy load loading message container is this:
<div id="#ajaxLoadContainerId" ...></div>
Then using the Razor engine we convert the parameters into a JSON and pass it on to the lazy load control.
var parameters = { limit: limit, fromRowNumber: fromRowNumber, #Html.Raw(parameters) };
var lazyLoad = new LazyLoad(containerId);
lazyLoad.init({
containerId: containerId,
ajaxLoadContainerId: ajaxLoadContainerId,
ajaxActionUrl: ajaxActionUrl,
parameters: parameters
});
Lastly, the fifth and sixth component are best explained through an example.
Say there are 15 entries of User in the database with these fields: Id, FirstName, LastName, Status and mapped to the model below. and we want to display the entries on the Home page in a progressive manner using the lazy load control.
using System.ComponentModel;
namespace RustyLazyLoadTester.Mobile.Services.Models
{
public class User
{
public User() { }
public User(long id, string firstName, string lastName, UserStatus status)
: this()
{
Id = id;
FirstName = firstName;
LastName = lastName;
Status = status;
}
public long Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public UserStatus Status { get; set; }
}
public enum UserStatus
{
[Description("All")]
All = 0,
[Description("Inactive")]
Inactive = 1,
[Description("Active")]
Active = 2,
[Description("Deactivated")]
Deactivated = 3
}
}
The first thing we need to do is create the service method:
using System.Collections.Generic;
using System.Linq;
using RustyLazyLoadTester.Mobile.Services.Models;
namespace RustyLazyLoadTester.Mobile.Services
{
public interface IQueryService
{
IEnumerable<User> GetAllUsers(UserStatus status = UserStatus.All,
int limit = 0, int fromRowNumber = 0);
}
class QueryService : IQueryService
{
public IEnumerable<User> GetAllUsers(UserStatus status, int limit, int fromRowNumber)
{
// Assume we have 15 users
var users = new List<User>();
for (var i = 0; i < 15; i++)
{
var userFirstName = string.Format("firstName_{0}", i);
var userLastName = string.Format("lastName_{0}", i);
var userStatus = i % 2 == 0 ? UserStatus.Active : UserStatus.Inactive;
users.Add(new User(i, userFirstName, userLastName, userStatus));
}
if (limit <= 0)
{
users = users.Where(x => x.Status == status)
.Skip(fromRowNumber)
.ToList();
}
else
{
users = users.Where(x => x.Status == status)
.Skip(fromRowNumber)
.Take(limit)
.ToList();
}
return users;
}
}
}
In our HomeController, we will need to create the default [HttpGet] Controller action method Index() for our Index page and the [HttpPost] Controller action method GetNextUsers() to serve the lazy loader:
using System;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using RustyLazyLoadTester.Mobile.Services;
using RustyLazyLoadTester.Mobile.Services.Models;
namespace RustyLazyLoadTester.Mobile.Controllers
{
public class HomeController : Controller
{
private readonly IQueryService _query;
public HomeController()
{
_query = new QueryService();
}
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult GetNextUsers(UserStatus status, int limit, int fromRowNumber)
{
try
{
var users = _query.GetAllUsers(status, limit, fromRowNumber);
if (!users.Any())
return Json(string.Empty);
return PartialView("_UserList", users);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return Json(ex.Message);
}
}
}
}
In Index.cshtml (the View corresponding to the [HttpGet] Controller action method Index()) we will have something like this:
#using RustyLazyLoadTester
#using RustyLazyLoadTester.Mobile.Models
#using RustyLazyLoadTester.Mobile.Services.Models
#{
ViewBag.PageTitle = "Home";
ViewBag.Title = string.Format("RustyLazyLoadTester - {0}", ViewBag.PageTitle);
var parameters = new Dictionary<string, object>();
parameters.Add("status", UserStatus.All);
}
#Scripts.Render("~/bundles/lazyload") #* points to /Scripts/rustylazyload.js *#
#Html.Partial("_RustyLazyLoad", new RustyLazyLoadViewModel(
5, 0, "ulUsers", Url.Action("GetNextUsers", "Home"), parameters))
The two bolded lines there will activate the lazy load control and trigger the GetNextUsers() on demand.
If we look closely on the second bolded line:
#Html.Partial("_RustyLazyLoad", new RustyLazyLoadViewModel(
5, 0, "ulUsers", Url.Action("GetNextUsers", "Home"), parameters))
The value 5 is the limit. This dictates how the number of items to be retrieved on each load. The value 0 is the fromRowNumber. This represents the N-th item in the result that needs to be ignored. As we load more data, this number will increase based on the loaded items, so we don't have to worry about duplicates (unless our code involves some complex sorting which makes it possible to have a new item in the middle of the list).
When GetNextUsers() method is called, it simply renders PartialView _UserList.cshtml below:
#using Humanizer
#using RustyLazyLoadTester.Mobile.Services.Models
#model IEnumerable<User>
#foreach (var user in Model)
{
<li class="ui-li ui-li-static ui-btn-up-b">
<div>#string.Format("First name: {0}", user.FirstName)</div>
<div>#string.Format("Last name: {0}", user.LastName)</div>
<div>#string.Format("Status: {0}", user.Status.Humanize())</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
<div>---</div>
</li>
}
Note that the content is wrapped in an . The reason for this is because the parent container (_containerId HTML object) is a . But we can always change this implementation very easily, as long as we maintain the hierarchy as below:
<parentContainer>
<childContainer>
[Content]
</childContainer>
</parentContainer>
This is because RustyLazyLoad control uses the parent container's number of children to update the _fromRowNumber property, which ensures there is no duplicate entry in the next load.
The above code is not written by me. But i have successfully used in my project. the reference is taken from the link where you have the complete description. All credits to Teddy Segoro . I have reposted it only for an information sharing. You can find the working model as

I haven't tried this yet but will be looking for a similar soultion soon: The term is called "lazy loading"
http://dcarrith.github.io/jquery.mobile.lazyloader/

Related

How to save table order row order after reordering it using kendo ui jquery? I dont know how to save the order into the database

// Kendo table sortable
var kendoSortable = grid.table.kendoSortable({
filter: ">tbody >tr",
hint: function (element) { // Customize the hint.
var table = $('<table style="width: 600px;" class="k-grid k-widget"></table>'),
hint;
table.append(element.clone()); // Append the dragged element.
table.css("opacity", 0.7);
return table; // Return the hint element.
},
cursor: "move",
placeholder: function (element) {
return $('<tr colspan="4" class="placeholder"></tr>');
},
change: function (e) {
var skip = grid.dataSource.skip(),
oldIndex = e.oldIndex + skip,
newIndex = e.newIndex + skip,
data = grid.dataSource.data(),
dataItem = grid.dataSource.getByUid(e.item.data("uid"));
grid.dataSource.remove(dataItem);
grid.dataSource.insert(newIndex, dataItem);
}
});
Im trying to save the order after dragging and reordering. to the database so that when i reload the page the order where i have ordered it would be the exact order when i am reaordering it
Look into using the change event for the Sortable widget. This event provides the oldIndex and newIndex positions for the item that was moved.
Below is an example of one way to go about getting the reordered items and then sending that data to the server to save the changes. Hopefully, this will help you get started with solving your problem.
The change event firing indicates the item has been sorted and the item's position has changed in the DOM. Looking at the change event below, I'm getting the data items for the current page of the grid into currentGridView. Then I'm using the slice() method to get the items between the oldIndex and newIndex. Then I call the updateSequence function.
The updateSequence function creates an array to store objects to be passed to the server. These objects are based on the DataSequenceModel class. Basically, I just need to know the Id and the new sequence for each item that has been reordered. After this I'm using a basic Ajax POST to send the data to the server.
Index.cshtml - Here is a dojo based on Telerik's Integration - Grid demo and updated with my changes.
<div id="grid"></div>
<script>
$(document).ready(function () {
var grid = $("#grid").kendoGrid({
// ...Basic grid setup
}).data("kendoGrid");
grid.table.kendoSortable({
filter: ">tbody >tr",
hint: $.noop,
cursor: "move",
placeholder: function(element) {
return element.clone().addClass("k-state-hover").css("opacity", 0.65);
},
container: "#grid tbody",
change: function (e) {
// Get the indexes and data items that have been reordered.
var skip = grid.dataSource.skip(),
oldIndex = e.oldIndex + skip,
newIndex = e.newIndex + skip;
var currentGridView = grid.dataSource.view();
var dataChanged = currentGridView.slice(oldIndex, newIndex + 1);
updateSequence(oldIndex, dataChanged);
}
});
});
function updateSequence(startIndex, dataChanged) {
// Create array to be passed to Controller. Based on DataSequenceModel class.
let data = [];
let newSequence = startIndex;
for (var i = 0; i < dataChanged.length; i++) {
data.push({ Id: dataChanged[i].ProductID, NewSequence: newSequence });
newSequence++
}
$.ajax({
type: "POST",
url: 'https://localhost:44395/Test/UpdateSequence',
contentType: 'application/json',
data: JSON.stringify(data),
success: function (data) {
console.log(data);
},
error: function (e) {
console.error(e);
}
});
};
</script>
TestController.cs
public class TestController : Controller
{
public ActionResult Index()
{
return View();
}
public bool UpdateSequence(IEnumerable<DataSequenceModel> data)
{
// ...Logic to update sequence in database.
return true;
}
}
DataSequenceModel.cs
public class DataSequenceModel
{
public int Id { get; set; }
public int NewSequence { get; set; }
}

How to stream mp3 file from a SQL Server database in ASP.NET MVC C#

How do I stream mp3 files from a SQL Server database to an ASP.NET MVC view in C#?
I am able to retrieve the file from the database successfully but I do not
know what data needs to be passed to the view and what properties I need to
set. I have tried playing with the data-sources in the view but still get a
"no file found" when I run the application.
I am not sure what the datasource should be. When I set the datasource to a path to a mp3 file locally, it works fine.
When I run the application I get a "No file found"
ASP.NET MVC controller:
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
var mp3 = new Mp3Files
{
DATA = (Byte[])dr["DATA"],
DATASCOURCE = dr
};
list.Add(mp3);
}
foreach (var item in list)
{
Mp3FilesList.Add(item);
}
return View("Loops", "_Layout", Mp3FilesList);
}
View:
<div data-thumb="Scripts/img/adg3.jpg" data-type="audio"
class="audioplayer-tobe skin-wave "
data-source="#item.DATASCOURCE" data-
scrubbg="../Scripts/waves2/adg3_mp3.png" data-
scrubprog="Scripts/waves2/wavesprog.png" data-
playfrom="last">
Mp3Files class:
{
public int AUDIO_ID { get; set; }
public string NAME { get; set; }
public string CONTENT_TYPE { get; set; }
public string BPM { get; set; }
public string CATEGORY { get; set; }
public Byte[] DATA { get; set; }
public DbDataReader DATASCOURCE { get; set; }
}
I know this post is quite old but as someone might come here after google research, I will share the way I've solved.
You have two options: by MVC (unfriendly if you have a lot of sounds to include in your page) or JQuery (you can create a loading animation to give user a friendly wait message or spinner, for example).
OPTION 1 - MVC (I've used the name of your View (Loops) and the code you posted):
public ActionResult Loops()
{
PageViewModel result = new PageViewModel();
IDataReader dr = null; // some SQL Search
result.Files = new List<Mp3File>();
while (dr.Read())
{
result.Files.Add(new Mp3File()
{
Id = int.Parse(dr["Id"].ToString()),
Name = dr["Name"].ToString(),
ContentType = dr["ContentType"].ToString(), //must be something like audio/mp3 for example
Category = dr["Category"].ToString(),
Data = (Byte[])dr["Data"]
});
}
return Json(result, JsonRequestBehavior.AllowGet);
}
Then, in your CSHTML file you loop through the files property of your ViewModel and point the data to the source of your audio HTML Element:
if (Model.Files?.Count > 0)
{
<div class="list">
#for (var i = 0; i < Model.Files.Count; i++)
{
<!-- AUDIO ITEM -->
<label class="item">
<span class="title"><i class="far fa-file-audio"></i> #Model.Files[i].Name</span>
<audio controls>
<source src="#Model.Files[i].Data" type="#Model.Files[i].ContentType" />
</audio>
</label>
}
</div>
}
JQuery Solution: In my personal opinion, this options is better because it is more user friendly and don't cause a long waiting white page:
1) If possible, store your files in your web server as the loading process will be way faster;
2) Create one HTTP Get Method in your Controller
[HttpGet]
public ActionResult GetFiles()
{
PageViewModel result = new PageViewModel();
IDataReader dr = null; // some SQL Search
result.Files = new List<Mp3File>();
while (dr.Read())
{
result.Files.Add(new Mp3File()
{
Id = int.Parse(dr["Id"].ToString()),
Name = dr["Name"].ToString(),
ContentType = dr["ContentType"].ToString(), //must be something like audio/mp3 for example
Category = dr["Category"].ToString(),
Data = (Byte[])dr["Data"],
Url = $"{Request.Url.GetLeftPart(UriPartial.Authority)}/assets/audio/{Path.GetFileNameWithoutExtension(dr["Name"].ToString())}.mp3" //in case you stored your file in your web server
});
}
return Json(result, JsonRequestBehavior.AllowGet);
}
3) Create a javascript function in your CSTHML page that will load your files
//In this example I'm using local JS for JQuery and Bootstrap. But you can use the way you prefer (CDN or NPM for example)
<!-- SCRIPTS -->
<script src="~/assets/js/jquery-3.3.1.slim.min.js"></script>
<script src="~/assets/js/bootstrap.min.js"></script>
<script>
$(document).ready(function () {
loadFiles();
});
function loadFiles() {
//here I'm referencing a DIV tag that uses the spinner.js has the following content:
$("#spinner").show();
//<div class="wrapper-loading" id="spinner" style="display:none;">
// <span class="spinner-double-section-far"></span>
//</div>
$.ajax({
async: true,
url: "GetFiles",
cache: false,
dataType: "json",
success: function (data) {
$("#spinner").hide(); //stop spinner
if (data) {
$("#audioContainer").show();
data.Files.forEach(audio => {
var newAudio = '<label class="item">';
newAudio += '<span class="title"><i class="far fa-file-audio"></i>' + audio.Name + '</span>';
newAudio += '<audio controls><source src="' + audio.Url + '" type="audio/mp3"/>';
newAudio += '</audio></label>';
$("#audioContainer").append(newAudio); //JQuery command to insert new HTML into some Element
});
}
},
error: function (error) {
$("#spinner").hide(); //stop spinner
alert(JSON.stringify(error));
}
});
}
</script>
That's all I needed to put some audio files in my page using the standard AUDIO HTML control that has embedded controls like play, pause, etc.
Good luck and hope it helps you.

Pass last insert id to toastr - Asp.Net MVC 4

I am new to MVC and trying to pass the last created Id (once the save button has been clicked in the form).
Can anyone please tell me if it is possible to pass this value to the toastr display, and how this can be done, so once the save button is pressed it returns that Id number?
Additionally to my comment, here's a more complex answer.
Roughly it contains the following items:
Views: CreateItem, NewItemHandler
Controllers: ItemHandler
Javascript: site.js and jQuery
The CreateItem view is the dialog where the user enters their item values. In my case a simple form with two input fields and the mandatory submit button.
#{
ViewBag.Title = "CreateItem";
}
<h2>CreateItem</h2>
<form id="newItemForm">
Item name: <input id="itemname" type="text" name="fname"><br>
Item weight: <input id="itemweight" type="text" name="lname"><br>
<input type="submit" value="Submit">
</form>
The JavaScript should stop the redirection when clicking on submit, this is done by returning false within $("newItemForm").submit(...). Furthermore we no need to tell the server that it needs to create our item, so we have to create our own submit request, which I did with jQuery.post():
$('#newItemForm').submit(function () {
sendPostAndShowResult();
return false;
});
function sendPostAndShowResult() {
var name = $("#itemname").text();
var weight = $("#itemweight").text();
$.post("/Item/NewItemHandler",
{ "name": name, "weight": weight }
).done(function (data) {
alert("The ID of your new item is: " + $.trim(data)); //replace with toast
})
.fail(function () {
alert("Error while processing the request!");
});
}
Just a hint: I didn't use toast here, since I never used it, but I guess it shouldn't be too difficult to adapt.
The final piece of the puzzle is the NewItemHandler, which creates the item, figures out the ID and returns the value:
The View is quite easy. Since we don't need a Layout, it has been set to "".
#{
Layout = "";
}
#Html.Raw(Session["ItemID"])
As you see, we just need to get the "ItemID" into our Session object, this is done by the Controller.
[HttpPost]
public ActionResult NewItemHandler(string name, string weight)
{
int id = GenerateNewItem(name, weight);
Session["ItemID"] = id;
return View();
}
EDIT: I tried to adapt this approach to your solution:
You need to remove the return RedirectToAction() with return View(); in your Controller. This then returns (Save.cshtml) a response, with the ID in an ohterwise empty file (Layout = "").
Your Save.cshtml is empty I guess, so replace it with
#{
Layout = "";
}
#Html.Raw(Session["ItemID"])
In your controller the Save Method should look remotely like this.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(BidstonHwrc bidstonhwrc)
{
_context.BidstonHwrc.Add(bidstonhwrc);
try
{
_context.SaveChanges(); //either all changes are made or none at all
}
catch (Exception e)
{
Console.WriteLine(e);
}
int id = bidstonhwrc.Id;
Session["ItemID"] = id;
return View();
}
In your MCN Form you need to give your <form> tag an ID, via Razor:
#using (Html.BeginForm("Save", "BidstonHwrc",FormMethod.Post, new { id = "SaveBidstonHwrc" }))
The javascript code should look like this, simply adapt the IDs:
$('#SaveBidstonHwrc').submit(function () {
sendPostAndShowResult();
return false;
});
function sendPostAndShowResult() {
//foreach Model/ViewModel Property one line e.g.
var Id = $("Id").text();
var McnNumber = $("McnNumber").text();
$.post("/BidstonHwrc/Save",
{ "Id": Id, "McnNumber": McnNumber }
).done(function (data) {
alert("The ID of your new item is: " + $.trim(data)); //replace with toast
$(location).attr('href', '/Home/Index') //Redirect to Home
})
.fail(function () {
alert("Error while processing the request!");
});
}
I uploaded a project that should represent your solution a bit.
You can download it here (28MB): Project download

DropDownListFor get selected item value as parameter to controller

Problem
I want my Html form to pass the value of the selected DropDownListFor to the controller but I can't figure out why the controller is not taking any value.
Im sending the value to the controller and trying to do some code with the selected value each time the user selects something but i can't manahe myselft to do it.
View
#Html.DropDownList("Fechas", "Todas")
<div id="target">
</div>
Javascript
$('#Fechas').on('change', function () {
dataTable.columns('.fechas').search(this.value).draw();
var datafecha = $(this).val();
});
$("#Fechas").change(function () {
var dateSelected = $("select option:selected").first().text();
$.get('#Url.Action("Index")',
{ id: dateSelected }, function (data) {
$("#target").html(data);
});
});
Controller
public ActionResult Index(string id)
{
var db = Context();
string dateday;
string lines;
List<string> listItem2 = new List<string>();
List<string> listadesumas = new List<string>();
foreach (var item in db.Pos.Select(l => l.Fecha).Distinct())
{
dateday = Convert.ToString(item);
lines = dateday.Split(' ')[0];
listItem2.Add(lines);
}
var fechas = new SelectList(listItem2.ToList());
ViewBag.Fechas = fechas;
////////////-------------------/////////////
if (id == //SOMETHING)
{
// To do code comes here, which takes selectGroup as parameter
}
////////////_----------------------////////////
return View("~/Views/HomePos/Index.cshtml",db.Pos.ToList());
}
So how can i get my selected id as a parameter to use it in my controler and change data on the view? im not fully atached to javascript so if you have other approaches i will appreciate any help

jQuery select2 with remote data and asp.net

I am using select2 library for replacing select boxes. I rearranged example 7 that you can find on Select2 library page (scroll down with id
$("#e7").select2 etc...). I made my own generic handler that return serialized json data:
GetData.asxh view :
public class GetData : IHttpHandler
{
public bool IsReusable
{
get
{
return false;
}
}
public class RecipesList
{
public int total { get; set; }
public List<TopRecipeTable> recipes { get; set; }
public RecipesList() { }
public RecipesList(int total, List<TopRecipeTable> recipes)
{
this.total = total;
this.recipes = recipes;
}
}
private string GenerateJsonSerializedObject(int languageId, string orderBy)
{
RecipesList recipeList = new RecipesList(15, DBDataBase.GetTopRecipesByNumberOfRecipes(languageId, 15));
return new JavaScriptSerializer().Serialize(recipeList);
}
public void ProcessRequest(HttpContext context)
{
int languageId;
bool languageParsed = int.TryParse(context.Request["languageId"], out languageId);
string orderBy = (string)context.Request["orderBy"];
if (languageParsed && orderBy != string.Empty)
{enter code here
context.Response.ContentType = "application/json";
var jsonValue = GenerateJsonSerializedObject(languageId, orderBy);
context.Response.Write(jsonValue);
}
}
This generic handler returns the right format of json (I checked it with this URL ). My result (json) is also the same as the one in example on above mentioned page. But after this jquery doesn`t fire anymore.
My script :
$(document).ready(function () {
$("#e8").select2({
placeholder: "Search for a recipe",
//minimumInputLength: 1,
ajax: {
url: "/Handlers/GetData.ashx",
dataType: 'jsonp',
data: function (term, page) {
return {
languageId: 1,
orderBy: "TA"
};
},
results: function (data, page) {
alert(data.total);
var more = (page * 10) < data.total; // whether or not there are more results available
// notice we return the value of more so Select2 knows if more results can be loaded
return { results: data.recipes, more: more };
}
},
formatResult: movieFormatResult, // omitted for brevity, see the source of this page
formatSelection: movieFormatSelection, // omitted for brevity, see the source of this page
dropdownCssClass: "bigdrop", // apply css that makes the dropdown taller
escapeMarkup: function (m) { return m; } // we do not want to escape markup since we are displaying html in results
});
});
I tried to write the same alert(data.total) in the original example and it worked but not in my version. So I have the right json format, the jquery calls my generic handler and also recieved parameters languageId ... and also return the right json format but than nothing. I don't know if I am missing something here, because I am sure that this thing could also work with a generic handler as well. I hope I gave enough information about my problem.
I can also add my result in jquery .ajax error handler :
xhr.status = 200
ajaxOptions = parsererror
horwnError = SyntaxError : invalid label
If this is any helpful information
This question is quite old, so pretty sure you have a solution by now...but:
Remove all of these functions:
formatResult: movieFormatResult
formatSelection: movieFormatSelection
dropdownCssClass: ...
escapeMarkup:....
You did not provide those functions to format your data did you? All of those are only needed if you are making a custom drop down of items.
You are returning data.recipes - that needs to be an array of {Text:"", Id:""} or you need to build it from what you return right there.
First, get it working with just a very basic list with very basic data...then go from there.
Additionally, when you get that working try using WebApi or ServiceStack to handle your data instead of an IHttpHandler.

Categories

Resources