I am using pagedList it is working but i need to have an ajax call to bring a new page i don't know how to do.
public ActionResult ApplicantsRecord(int page =1)
{
List<ApplicantsRecord> ar = new List<ApplicantsRecord>();
ApplicantsRecord a = new ApplicantsRecord();
List<ApplicantsRecordDetailViewModel> apvmlist = new List<ApplicantsRecordDetailViewModel>();
ApplicantsRecordDetailViewModel apvm = new ApplicantsRecordDetailViewModel();
//ar = db.ApplicantsRecords.ToList();
var groupedAR = db.ApplicantsRecords.GroupBy(x => x.SessionId)
.Select(y => new
{
SessionId = y.Key,
ApplicationsRecords = y.FirstOrDefault(),
}).ToList().OrderByDescending(x => x.ApplicationsRecords.LoginDate);
foreach (var i in groupedAR)
{
ar.Add(i.ApplicationsRecords);
}
if(Request.IsAjaxRequest())
{
return PartialView("_ApplicantsRecord", ar.ToPagedList(page, 10));
}
return View(ar.ToPagedList(page, 10));
}
and here is the view code
<div id="pagerecord">
#Html.Partial("_ApplicantsRecord");
</div>
<script src="~/Scripts/jquery-2.1.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var getpage = function () {
var $a = $(this);
var options = {
url: $a.attr("href"),
type: "get"
};
$.ajax(options).done(function (data) {
var target = $a.parents("div.pagedList").attr("next");
$(target).replaceWith(data);
});
return false;
};
$('main-conten').on('click', '.pagedList', getpage)
});
</script>
and here is the partial view
<table>
<thead>
<tr>
<th width="220" align="center">
<div class="pagedList" data-back-btn-text="next">
#Html.PagedListPager(Model, page => Url.Action("ApplicantsRecord", new { page }),
PagedListRenderOptions.MinimalWithItemCountText)
</div>
</th>
#*<th width="220" align="center">#Html.DisplayNameFor(model => model.UserName)</th>
<th width="220" align="center">#Html.DisplayNameFor(model => model.LoginDate)</th>
<th width="220" align="center">Details</th>*#
</tr>
</thead>
Did you try this already?
var getpage = function () {
var $a = $(this);
$.ajax({
url: $a.attr("href"),
type: "get",
success: function(data) {
var target = $a.parents("div.pagedList").attr("next");
$(target).replaceWith(data);
},
error: function() {
return false;
}
});
};
Next what you need tot do is:
Try to figure out if the data you are receiving is really the data you are expecting.
See if you do not enter the error function.
The first thing wrong is your selector is not a valid selector. $('main-conten') should probably be $('#main-conten') (assuming it is an element with an id of main-conten).
Secondly, you are using a delegated event handler, but listening for clicks on the .pagedList element and not the anchors within it:
$('main-conten').on('click', '.pagedList', getpage)
but inside the handler you are expecting the anchor to have been clicked as you are using:
var $a = $(this);
and
$a.attr("href")
Try something like this:
$(function () {
// Listen for clicks on anchors inside the paging panel
$('#main-conten').on('click', '.pagedList a', function () {
var $a = $(this);
var options = {
url: $a.attr("href"),
type: "get"
};
$.ajax(options).done(function (data) {
// Do something with the returned data
var target = $a.closest("div.pagedList").attr("next");
$(target).replaceWith(data);
});
return false;
});
});
Notes:
$(function () {YOUR CODE HERE}); is just a handy shortcut for $(document).ready(function(){});
Use closest() in preference to parents() where you only expect a single matching ancestor.
If all this still does not work, please post your HTML output (not source) as saved from the browser.
Related
I have an ASP.NET Core 3.1 Web App that has functionality where a user can input a stock ticker and a chart is created for them using a query to retrieve data (Price & Date) for that ticker. I've followed basic Google Chart API walkthroughs to implement in my app. It works if the data is hardcoded in the JSON method, but if I want to dynamically view a chart based on whatever ticker I enter, the chart doesn't receive the JSON data needed.
What I tried was having a Ticker Entry page (Action method) with a Form that returns the user inputted ticker to the Chart action method. What I wanted was for the Chart method to handle all the LINQ Querying and transforming the list into a JSONList, so that it can be passed into it's View method. I'll post the code in order.
TickerEntry.cshtml
#using (Html.BeginForm("Chart", "Stocks", FormMethod.Get))
{
<table>
<tr>
<td>Enter a Ticker to pull up its chart: </td>
<td>#Html.TextBox("stockTicker")</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit"></td>
</tr>
</table>
}
StocksController.cs
public List<StockLineChart> GetStockData(string stockTicker)
{
var list = new List<StockLineChart>();
var result = (from s in _context.HistoricalDatas
where s.Ticker == stockTicker
select new { s.Price, s.DateOfClose });
list = result.AsEnumerable()
.Select(sl => new StockLineChart
{
Price = sl.Price,
DateOfClose = Convert.ToDateTime(sl.DateOfClose)
}).ToList();
return list;
}
public IActionResult TickerEntry()
{
return View();
}
public IActionResult Chart(string stockTicker)
{
//Returns the Chart View, but passes in the list of stock price&date transformed into JSON
return View(GetLineChartJSON(GetStockData(stockTicker)));
}
public JsonResult GetLineChartJSON(List<StockLineChart> stockList)
{
return Json(new { JSONList = stockList });
}
Chart.cshtml
#{
ViewData["Title"] = "Chart";
}
<div class="row">
<div class="col-lg-12">
<div id="chartdiv" style="width:1000px;height:350px;">
</div>
</div>
</div>
#section Scripts
{
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
// Load the Visualization API and the corechart package.
google.charts.load('current', { 'packages': ['corechart'] });
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(DrawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function DrawChart() {
$(function () {
$.ajax({
type: 'GET',
url: '/Stocks/GetLineChartJSON',
success: function (chartsdata) {
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
//get jsonList from Object
var Data = chartsdata.jsonList;
var data = new google.visualization.DataTable();
data.addColumn('string', 'DateOfClose');
data.addColumn('number', 'Price');
//Loop through each list data
for (var i = 0; i < Data.length; i++) {
data.addRow([Data[i].dateOfClose, Data[i].price]);
}
// Instantiate and draw our chart, passing in some options
var chart = new google.visualization.LineChart(document.getElementById('chartdiv'));
//Draw line chart command with data and chart options
chart.draw(data,
{
title: "Stock Chart",
position: "top",
fontsize: "14px",
});
},
error: function () {
alert("Error loading data! Please try again.");
}
});
})
}
</script>
}
What I believe is that the GetLineChartJSON shouldn't take any parameters, but it's hard to do this because it needs some type of data(Either a ticker to query the list, or the list itself so it can transform into JSON)
For example, this would work:
StockController.cs
public JsonResult GetLineChartJSON()
{
var list = new List<StockLineChart>();
var result = (from s in _context.HistoricalDatas
where s.Ticker == "AC"
select new { s.Price, s.DateOfClose });
list = result.AsEnumerable()
.Select(sl => new StockLineChart
{
Price = sl.Price,
DateOfClose = Convert.ToDateTime(sl.DateOfClose)
}).ToList();
return Json(new { JSONList = list });
}
Note that there's nothing passed into this method, and stockTicker has now been hardcoded in as "AC", which I don't want, because the user chooses what stock they want to see.
I hope I'm not confusing with the explanation of my problem, I'm willing to clarify any misunderstanding.
A whole working demo here you could follow:
Chart.cshtml
#{
ViewData["Title"] = "Chart";
}
<div class="row">
<div class="col-lg-12">
<div id="chartdiv" style="width:1000px;height:350px;">
</div>
</div>
</div>
#section Scripts
{
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', { 'packages': ['corechart'] });
google.charts.setOnLoadCallback(DrawChart);
function DrawChart() {
$(function () {
var Data = #Html.Raw(ViewBag.StockTicker); //get the ViewBag object
var data = new google.visualization.DataTable();
data.addColumn('string', 'DateOfClose');
data.addColumn('number', 'Price');
for (var i = 0; i < Data.length; i++) {
//change uppercase here....
data.addRow([Data[i].DateOfClose, Data[i].Price]);
}
var chart = new google.visualization.LineChart(document.getElementById('chartdiv'));
chart.draw(data,
{
title: "Stock Chart",
position: "top",
fontsize: "14px",
});
})
}
</script>
}
Controller
public IActionResult TickerEntry()
{
return View();
}
public List<StockLineChart> GetStockData(string stockTicker)
{
var list = new List<StockLineChart>();
var result = (from s in _context.HistoricalDatas
where s.Ticker == stockTicker
select new { s.Price, s.DateOfClose });
list = result.AsEnumerable()
.Select(sl => new StockLineChart
{
Price = sl.Price,
DateOfClose = Convert.ToDateTime(sl.DateOfClose)
}).ToList();
return list;
}
public IActionResult Chart(string stockTicker)
{
//Use ViewBag instead....
ViewBag.StockTicker =JsonConvert.SerializeObject(GetStockData(stockTicker));
return View();
}
//no need GetLineChartJSON method any more....
I'm trying to write CRUD operations using ajax. Here some code:
These are my View classes:
//PhotoSummary
#model PhotoAlbum.WEB.Models.PhotoViewModel
<div class="well">
<h3>
<strong>#Model.Name</strong>
<span class="pull-right label label-primary">#Model.AverageRaiting.ToString("# stars")</span>
</h3>
<span class="lead">#Model.Description</span>
#Html.DialogFormLink("Update", Url.Action("UpdatePhoto", new {photoId = #Model.PhotoId}), "Update Photo", #Model.PhotoId.ToString(), Url.Action("Photo"))
</div>
//Main View
#model PhotoAlbum.WEB.Models.PhotoListViewModel
#{
ViewBag.Title = "My Photos";
}
#foreach (var p in #Model.Photos)
{
<div id=#p.PhotoId>
#Html.Action("Photo", new {photo = p})
</div>
}
The sript:
$('.dialogLink').on('click', function () {
var element = $(this);
var dialogTitle = element.attr('data-dialog-title');
var updateTargetId = '#' + element.attr('data-update-target-id');
var updateUrl = element.attr('data-update-url');
var dialogId = 'uniqueName-' + Math.floor(Math.random() * 1000)
var dialogDiv = "<div id='" + dialogId + "'></div>";
$(dialogDiv).load(this.href, function () {
$(this).dialog({
modal: true,
resizable: false,
title: dialogTitle,
close: function () { $(this).empty(); },
buttons: {
"Save": function () {
// Manually submit the form
var form = $('form', this);
$(form).submit();
},
"Cancel": function () { $(this).dialog('close'); }
}
});
$.validator.unobtrusive.parse(this);
wireUpForm(this, updateTargetId, updateUrl);
});
return false;
});});
function wireUpForm(dialog, updateTargetId, updateUrl) {
$('form', dialog).submit(function () {
if (!$(this).valid())
return false;
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$(dialog).dialog('close');
$(updateTargetId).load(updateUrl);
} else {
$(dialog).html(result);
$.validator.unobtrusive.parse(dialog);
wireUpForm(dialog, updateTargetId, updateUrl);
}
}
});
return false;
});
}
And here my Tag builder:
public static MvcHtmlString DialogFormLink(this HtmlHelper htmlHelper, string linkText, string dialogContentUrl,
string dialogTitle, string updateTargetId, string updateUrl)
{
TagBuilder builder = new TagBuilder("a");
builder.SetInnerText(linkText);
builder.Attributes.Add("href", dialogContentUrl);
builder.Attributes.Add("data-dialog-title", dialogTitle);
builder.Attributes.Add("data-update-target-id", updateTargetId);
builder.Attributes.Add("data-update-url", updateUrl);
builder.AddCssClass("dialogLink");
return new MvcHtmlString(builder.ToString());
}
So, I have major problem if the dialog was called twice without the calling page being refreshed:
it just redirects me to the action page.
The question is how to update #Html.Action without reloading the page?
Could anyone help me?
Your #foreach loop in the main view is generating a partial view for each Photo which in turn is creating a link with class="dialogLink".
Your script handles the click event of these links and replaces it with a new link with class="dialogLink". But the new link does not have a .click() handler so clicking on the new (replacement) link does not activate your script.
Instead you need to use event delegation to handle events for dynamically generated content using the .on() method (refer also here for more information on event delegation). Note also that your current use of $('.dialogLink').on('click', function () { is the equivalent of $('.dialogLink').click(function () { and is not using event delegation. It attaches a handler to elements that exist in the DOM at the time the page is loaded, not to elements that might be added in the future.
Change your html to
<div id="photos">
#foreach (var p in #Model.Photos)
{
<div class="photo">#Html.Action("Photo", new { photo = p })</div>
}
</div>
and then modify the script to
$('#photos').on('click', '.dialogLink', function() {
....
});
Side note: There is no real need to add an id=#p.PhotoId to the containing div element and you could use <div class="photo"> as per above, and then reference it by using var updateTargetId = $(this).closest('.photo'); and delete the builder.Attributes.Add("data-update-target-id", updateTargetId); line of code from your DialogFormLink() method
When I make ajax request to the server with breakpoint in the action method it stops on this breakpoint only the first time. After clicking for second, third etc. it goes but never stops on this breakpoint. When I change the method from GET to POST it stops every time. What is the reason for this behaviour ?
CLIENT SIDE:
$(function () {
setListAction();
});
function setListAction() {
$("li.list").on("click", function () {
alert("active");
var id = $(this).attr("file-id");
$.ajax({
type: "GET",
url: "TechAcc/ManageFile/" + id,
beforeSend: function myfunction() {
$("#loading").css("display", "block");
$("#fade").css("display", "block");
},
success: function (data) {
var content = $(data).find("div#content");
$("div#content").html(content.html());
$("#loading").css("display", "none");
$("#fade").css("display", "none");
}
});
});
}
SERVER SIDE:
[HttpGet]
public ActionResult ManageFile(int id = 0)
{
FileModel model = null;
if (id != 0)
model = new FileModel() { File = _repository.GetFileBy(id), GetAllFiles = _repository.GetAllFiles() };
else if (Session["Model"] != null)
model = (FileModel)Session["Model"];
else
model = new FileModel() { GetAllFiles = _repository.GetAllFiles() };
return View(model);
}
if your div with id "content" has list, it will not work.
<div id="content">
if your list is here, it won't work.
...
<li class="list">...</li>
...
</div>
if your design is like that, you need to bind click event after you replace your HTML response. i.e.,
success: function (data) {
var content = $(data).find("div#content");
$("div#content").html(content.html());
//adding code here.
$("div#content").find("li.list").on("click", function() {
//same above click code should come here.
//Note: this newly added code block should not come here in click.
});
$("#loading").css("display", "none");
$("#fade").css("display", "none");
}
I need to be able to populate data into a <div> or some other sort of section from an object after the corresponding string has been selected from a drop down list (lazy loading).
When a chnage is made in the dropdownlist, I want the method in my controller to be called which will fill in <div id=result></div> with the output from the method.
Perhaps I am approaching this problem wrong.
I suspect the problem is in my JavaScript.
Here is my approach:
View:
<div>#Html.DropDownList("MyDDL") </div>
<br>
<div id="result"></div>
JavaScript:
<script type ="text/javascript">
$(document).ready(function () {
$("#MyDDL").change(function () {
var strSelected = "";
$("#MyDDL option:selected").each(function () {
strSelected += $(this)[0].value;
});
var url = "HomeController/showInfo";
//I suspect this is not completely correct:
$.post(url, {str: strSelected},function (result) {
$("result").html(result);
});
});
});
</script>
Controller (Perhaps I shouldn't be using PartialViewResult):
public ActionResult Index()
{
List<string> myList = new List<string>();
List<SelectListItem> MyDDL = new List<SelectListItem>();
myList.Add("Tim");
myList.Add("Joe");
myList.Add("Jim");
//fill MyDDL with items from myList
MyDDL = myList
.Select(x => new SelectListItem { Text = x, Value = x })
.ToList();
ViewData["MyDDL"] = MyDDL;
return View();
}
[HttpPost]
public PartialViewResult showInfo(string str)
{
Person p = new Person(str); //name is passed to constructor
p.LoadInfo(); //database access in Person Model
ViewBag.Info = p.Info;
return PartialView("_result");
}
_result.cshtml:
<p>
#ViewBag.Info
</p>
Thanks You.
Change your script a little bit. Missing a # in the jQuery selecter for result div . Use the code given below
$.post(url, {str: strSelected},function (result) {
$("#result").html(result);
});
In my opinion if the javascript are in local don't need put $.post(url, {str: strSelected},function (result) {
You can use
//I suspect this is not completely correct:
$("#result").html(result);
try it
Did you try debugging p.LoadInfo() if it has any value? I also have some suggestions for your script:
Try adding keyup in your event so you can get the value in cases when the arrow keypad is used insted of clicking:
$("#MyDDL").on("change keyup", function () {
// you can get the dropdown value with this
var strSelected = $(this).val();
So I made the following changes and it worked:
View:
<div><%= Html.DropDownList("MyDDL") %> </div>
<br>
<span></span>
JavaScript:
<script type ="text/javascript">
$(document).ready(function () {
$("#MyDDL").change(function () {
var strSelected = $("#MyDDL option:selected").text();
var url = "/Home/showInfo";
$.post(url, {str: strSelected},function (result) {
$("span").html(result);
});
});
});
_result.cshtml:
#ViewBag.Info
The Controller was left unchanged.
I have a partial view that I am calling on pages as follows :-
#Html.Partial("~/Views/Shared/ImageGallery.cshtml", Model)
The code for the actual Jquery of this page is a s follows :-
<script type="text/javascript">
$(document).ready(function () {
$('.modal_block').click(function (e) {
$('#tn_select').empty();
$('.modal_part').hide();
});
$('#modal_link').click(function (e) {
$('.modal_part').show();
var context = $('#tn_select').load('/Upload/UploadImage?Page=Article&Action=Edit&id=16', function () {
initSelect(context);
});
e.preventDefault();
return false;
});
});
</script>
Now this works perfectly, however I need to find a way to pass dynamic vars instead of hard coded vars to this :-
Upload/UploadImage?Page=Article&Action=Edit&id=16
In the Model I have all the vars, however I do not know how I can insert them into the Jquery. Any help would be very much appreciated!
---------UPDATE-----------------------
This is the code I am putting into each cshtml that needs the ImageGallery.
</div>
#Html.HiddenFor(model => model.PageViewModel.Page.PageTitle, new { id = "PageTitle"});
#Html.HiddenFor(model => model.PageViewModel.Page.PageAction, new { id = "PageAction"});
#Html.HiddenFor(model => model.ArticleViewModel.Article.ArticleID, new { id = "ArticleID"});
<div>
#Html.Partial("~/Views/Shared/ImageGallery.cshtml", Model)
</div>
New Javascript in the ImageGallery :-
<script type="text/javascript">
var pageTitle = $('#PageTitle').val();
var pageAction = $('#PageAction').val();
var id = $('#ArticleID').val();
$(document).ready(function () {
$('.modal_block').click(function (e) {
$('#tn_select').empty();
$('.modal_part').hide();
});
$('#modal_link').click(function (e) {
$('.modal_part').show();
var context = $('#tn_select').load('/Upload/UploadImage?Page=' + pageTitle + '&Action=' + pageAction + '&id=' + id, function () {
initSelect(context);
});
e.preventDefault();
return false;
});
});
</script>
This works fine now
You can add hidden field to your view and bind data form the model. Then you can easily read this value from jQuery.
View:
#Html.HiddenFor(model => model.Id, new { id = "FieldId"});
Script:
var id= $('#FieldId').val();
Also you can put this hiddens into your partial view. If your partial view is not strongly typed change HiddenFor to Hidden. Your ImageGallery partial view should contain the following div:
</div>
#Html.Hidden("PageTitle", Model.PageViewModel.Page.PageTitle);
#Html.Hidden("PageAction", Model.PageViewModel.Page.PageAction);
#Html.Hidden("ArticleID", Model.ArticleViewModel.Article.ArticleID);
<div>
In this case you don't need to put hiddens to every cshtml that needs the ImageGallery.
You can either set hidden fields or just declare javascript variables and set their values from either your model or the Viewbag, just like:
var action = #Model.action;
or
var id = #ViewBag.id;
and you can just use it in your code
<script type="text/javascript">
var action = #Model.action;
var id = #ViewBag.id;
$(document).ready(function () {
$('.modal_block').click(function (e) {
$('#tn_select').empty();
$('.modal_part').hide();
});
$('#modal_link').click(function (e) {
$('.modal_part').show();
var urlToLoad = "/Upload/UploadImage?Page=Article&Action=" + action + "&id=" + id;
var context = $('#tn_select').load(urlToLoad, function () {
initSelect(context);
});
e.preventDefault();
return false;
});
});
The following is another solution. I was in need of passing my api url declared in web.config to JavaScript (in this case Jquery)
In Razor declare a variable
#{var apiUrl= #System.Configuration.ConfigurationManager.AppSettings["BlogsApi"];}
Then in JavaScript
var apiUrl = '#apiUrl';