RenderPartial will not fire controller ActionResult Method - asp.net

I have a Razor view containing a partial view that I want to update when the user clicks the refresh button on my pop up
The code executes with no errors, but my breakpoint in the controller method PricingUpdate does not fire. If I add alerts to my JavaScript this tells me the Javascript is firing OK
I can't see anything wrong with what I have, I am suspicious of the url variable string value, i.e. var url = 'Supplypoint/PricingUpdate'; but i've tried many variations
My Controller Method :
public ActionResult PricingUpdate(DateTime StartDate,DateTime EndDate, int SupplyPointId)
{
var obj = _db.GetSupplyPoint(SupplyPointId);
_db.SupplyPointCalculateWastePricing(obj, StartDate, EndDate);
_db.SupplyPointCalculatePricing(obj, StartDate, EndDate);
var supplyPoint = _db.GetSupplyPoint(SupplyPointId);
return PartialView("_DetailsPricing", supplyPoint);
}
My main View code extract :
<div id="ResultsList" style="clear:both;">
#{Html.RenderPartial("_DetailsPricing", Model);}
</div>
My script code in the main View :
$("#RefreshBtn").click(function () {
var url = 'Supplypoint/PricingUpdate';
var data = {
StartDate: $('#StartDate').val(),
EndDate: $('#EndDate').val(),
SupplyPointId: $('#SupplyPointId').val().toString()
};
$("#ResultsList").load(url,data,function () {
$('#LoadingGif').empty();
});
$('#LoadingGif').empty().html('<img src="/Content/images/ajax-loader.gif" width=31 height=31 alt="Loading image" />');
});

Yikes I had called my date inputs by the wrong name, changed code to : (all ok now)
var data = {
StartDate: $('#from').val(),
EndDate: $('#to').val(),
SupplyPointId: $('#SupplyPointId').val().toString()
};

Related

ASP.NET MVC: How to send the ids of the DOM Body elements on the client's browser TO the controller when navigating from the view

I am working on an ASP.NET MVC app (ASP.NET NOT ASP.NET Core).
When a View is rendered, the user can click on some buttons on the page to collapse or show divs associated with each button. The div changes its class depending on whether it is collapsed or shown. I am using bootstrap attributes for this, and it works fine.
Now I have a "Save" button on the page. When the user clicks on this button, I need to retrieve the ids and classes of the divs, and pass them TO the Controller (in an array/collection/dictionary whatever).
Is there a way/method in ASP.NET to send to the Controller the attributes (ids, classes, etc) of the DOM elements on the client's browser ?
Thanks
If you want to send some attributes of DOM to Controller, I have a way.
HTML:
<div id="demo-1" class="chosendiv other-className" data-code ="abc">Lorem Ipsum</div>
<div id="demo-2" class="chosendiv other-className" data-code ="xyz">Lorem Ipsum</div>
<div id="demo-3" class="other-className" data-code ="mnt">Lorem Ipsum</div>
<button id="btn-save" onclick="Save()">SAVE</button>
Javascript
<script>
function Save(){
var cds = document.getElementsByClassName('chosendiv');
var finder = [];
if(cds != null){
for(i = 0; i< cds.length; i++){
finder.push({
ID: cds[i].getAttribute('id'),
ClassName: cds[i].getAttribute('class'),
Code: cds[i].getAttribute('data-code')
})
}
}
//
// Send finder to Controller. You can use Ajax...
// A simple ajax call:
//
$.ajax({
url: '/Home/YourAction',
type: 'GET', //<---- you can use POST method.
data:{
myDiv: JSON.stringify(finder)
},
success: function(response){
// Your code
}
})
}
</script>
Your Controller
public class HomeController: Controller
{
public HomeController(){}
[HttpGet]
public void YourAction(string myDiv)
{
//A lot of ways for converting string to Object, such as: creating new class for model, ...
// I use Dictionary Class
List<Dictionary<string, string>> temp = new List<Dictionary<string, string>>();
if(!string.IsNullOrEmpty(myDiv))
{
try
{
temp = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(myDiv);
}
catch { // Do something if it catches error. }
}
// Get a element (at index) from temp if temp.Count()>0
// var id = temp.ElementAt(index)["ID"];
// var className = temp.ElementAt(index)["ClassName"];
// var code = temp.ElementAt(index)["Code"];
//
//Your code
//
}
//......
}
It would be great if my answer could solve your problem.
Based on the answer provided by #Gia Khang
I made few changes in order to avoid the issue of the length of the URL exceeding the maximum limit.
Instead of adding the element's classes to an array using JS, I add them to a string :
function Save() {
var cds = document.getElementsByClassName('chosendiv');
// I use as string instead of an array
var finder = "";
if(cds != null){
for(i = 0; i< cds.length; i++){
finder = finder + "id=" + cds[i].getAttribute('id') + "class=" + cds[i].getAttribute('class') + "data-code=" +cds[i].getAttribute('data-code')
}
}
// Send finder to Controller. You can use Ajax...
// A simple ajax call:
var myURL = "/{Controller}/{Action}"
$.ajax({
url: myURL,
type: "POST",
data: { ids:finder },
success: function (response) {
}
})
}
In the Controller Action I add a parameter named "ids" (this must be the same name as the identifier of the data object in the post request)and I extract the id, class, and data value from the ids string by a method in one of my Models classes (sorry I work with VB.NET not with C# and it will take me a lot of time to convert the code to C#. I use the Split method in VB to split the ids string several times: a first one by using "id=" as delimiter, then spiting each element in the resulting array by the second delimiter "class=", etc. I add the resulting elements to a collection)
The Controller Action looks like this:
public class HomeController: Controller
{
public HomeController(){}
[HttpPost]
public void YourAction(string ids)
{
Models.myClass.splitStringMethod(ids)
Return View()
}
}

mvc pagedlist page number not incrementing

I'm using MVC 5 along with PagedList.MVC 4.5.0.0, I have data coming back and displaying on my table, along with the pager controls showing up. when I click next though, the pager continues to send page = 1 to my function, see that while debugging.
my page has:
<div class="pagedList" data-otf-target="#contractList">
#Html.PagedListPager(Model, page => Url.Action("Index", new { page }), PagedListRenderOptions.MinimalWithItemCountText)
</div>
my method which sends the data back to the action is
public IPagedList<ContractViewModel> GetAllContracts(int page = 1)
{
var lstcontractViewModel = new List<ContractViewModel>();
using (ContractRepository contractRepos = new ContractRepository(new UnitOfWork()))
{
var activeContractList = contractRepos.All.OrderByDescending(x => x.Id);
foreach (var activeContract in activeContractList)
{
Mapper.CreateMap<DomainClasses.ActiveContract, ActiveContractViewModel>().ForMember(dest => dest.ContractorModel, opts => opts.Ignore());
Mapper.AssertConfigurationIsValid();
lstcontractViewModel.Add(Mapper.Map<ActiveContractViewModel>(activeContract));
}
}
return lstcontractViewModel.ToPagedList(page, 40);
}
and my controller's action is
public ActionResult Index()
{
var contracts = activeaccountController.GetAllContracts();
return View(contracts);
}
as I said everything comes up fine for the 1st page, just when the GetAllContracts method is called, the debugger shows page is always = 1. so paging is always returning just the 1st page of results. i have over 2500 records, so other data is there, as the pager also shows that, pager says "Showing items 1 through 40 of 2546."
#Html.PagedListPager(Model, page => Url.Action("Index", new { page }), PagedListRenderOptions.MinimalWithItemCountText)
try to set new{page = somevalue} and it will send in a param.
Public ActionResult Index(int page)
public IPagedList<ContractViewModel> GetAllContracts(int page = 1)
This means that page is default 1 if no other param is applied.
var contracts = activeaccountController.GetAllContracts(page);
For more info read https://github.com/TroyGoode/PagedList

How to update the view when clic in javascript?

In my razor view, my model has one property composed only by a get.
#model Contoso.MvcApplication.ViewModels.QuizCompletedViewModel
<p>#Model.Property1</p>
By default, this property starts with the value: 10. And all the time has that value in view. I would like when I press clic on a img tag, this property can be updated (because all the time the value persisted), how can I update the property without refresh the page?
Step 1) Modify the view to make the counter addressable by jquery:
#model Contoso.MvcApplication.ViewModels.QuizCompletedViewModel
<p id="my-counter">#Model.Property1</p>
Now, do you need this incremented value on the server?
IF YOU DO NOT need this incremented value sent to the server:
Step 2) Increment the value on the client using javascript/jquery:
$("#my-image").click(function () {
var theValue = parseInt($("#my-counter").html());
theValue = theValue + 10;
$("#my-counter").html(theValue);
});
IF YOU DO NEED TO INCREMENT ON THE SERVER:
Step 2) Create a controller action to handle the increment
public ActionResult Increment(int currentValue)
{
// save to the database, or do whatever
int newValue = currentValue + 10;
DatabaseAccessLayer.Save(newValue);
Contoso.MvcApplication.ViewModels.QuizCompletedViewModel model = new Contoso.MvcApplication.ViewModels.QuizCompletedViewModel();
model.Property1 = newValue;
// If no exception, return the new value
return PartialView(model);
}
Step 3) Create a partial view which will return ONLY the new value
#model Contoso.MvcApplication.ViewModels.QuizCompletedViewModel
#Model.Property1
Step 4) Modify the jquery to post to this new action, which returns the new count, and displays it
$("#my-image").click(function () {
$.get('/MyController/Increment/' + $("#my-counter").html(), function(data) {
$("#my-counter").html(data);
});
});
Code is untested, but I think pretty close, and hopefully this gives the right idea.

Show alert after postback

I have a button which calls stored procedure and binds gridview.
I found a code on stackoverflow for top alert bar like this:
function topBar(message) {
var alert = $('<div id="alert">' + message + '</div>');
$(document.body).append(alert);
var $alert = $('#alert');
if ($alert.length) {
var alerttimer = window.setTimeout(function () {
$alert.trigger('click');
}, 10000);
$alert.animate({ height: $alert.css('line-height') || '50px' }, 500).click(function () {
window.clearTimeout(alerttimer);
$alert.animate({ height: '0' }, 200);
});
}
}
Then in my button I try to call this function like this:
Dim script As String = String.Format("topBar({0});", Server.HtmlEncode("Successfully Inserted"))
Response.Write(script) 'Or even like this
ClientScript.RegisterStartupScript(Page.GetType(), "topBar", script, True)
But it simply does not work.
Can you guide me in right direction?
I always sort this type of problems with supplying a Boolean Property whether javascript should fire a piece of script or not. For example :
public bool IsDone { get; set; }
Sorry that the code is in C#
This is a property on code behind file. When I need to fire the javascript method, I simply make this true.
What I do on the aspx page is as follows :
<script>
if(<%= IsDone.ToString().ToLower() %>) {
alert("Done!");
}
</script>

asp.net mvc - how to update dropdown list in tinyMCE

Scenario: I have a standard dropdown list and when the value in that dropdownlist changes I want to update another dropdownlist that exists in a tinyMCE control.
Currently it does what I want when I open the page (i.e. the first time)...
function changeParent() {
}
tinymce.create('tinymce.plugins.MoePlugin', {
createControl: function(n, cm) {
switch (n) {
case 'mylistbox':
var mlb = cm.createListBox('mylistbox', {
title: 'Inserts',
onselect: function(v) {
tinyMCE.execCommand("mceInsertContent",false,v);
}
});
<% foreach (var insert in (ViewData["Inserts"] as List<String>)) { %> // This is .NET
yourobject = '<%= insert %>'; // This is JS AND .NET
mlb.add(yourobject, yourobject); // This is JavaScript
<% } %>
// Return the new listbox instance
return mlb;
}
return null;
}
});
<%= Html.DropDownList(Model.Record[184].ModelEntity.ModelEntityId.ToString(), ViewData["Containers"] as SelectList, new { onchange = "changeParent(); return false;" })%>
I am thinking the way to accomplish this (in the ChangeParentFunction) is to call a controller action to get a new list, then grab the 'mylistbox' object and reassign it, but am unsure how to put it all together.
As far as updating the TinyMCE listbox goes, you can try using a tinymce.ui.NativeListBox instead of the standard tinymce.ui.ListBox. You can do this by setting the last argument to cm.createListBox to tinymce.ui.NativeListBox. This way, you'll have a regular old <select> that you can update as you normally would.
The downside is that it looks like you'll need to manually hook up your own onchange listener since NativeListBox maintains its own list of items internally.
EDIT:
I played around a bit with this last night and here's what I've come up with.
First, here's how to use a native list box and wire up our own onChange handler, the TinyMCE way:
// Create a NativeListBox so we can easily modify the contents of the list.
var mlb = cm.createListBox('mylistbox', {
title: 'Inserts'
}, tinymce.ui.NativeListBox);
// Set our own change handler.
mlb.onPostRender.add(function(t) {
tinymce.dom.Event.add(t.id, 'change', function(e) {
var v = e.target.options[e.target.selectedIndex].value;
tinyMCE.activeEditor.execCommand("mceInsertContent", false, v);
e.target.selectedIndex = 0;
});
});
As far as updating the list box at runtime, your idea of calling a controller action to get the new items is sound; I'm not familiar with ASP.NET, so I can't really help you there.
The ID of the <select> that TinyMCE creates takes the form editorId_controlId, where in your case controlId is "mylistbox". Firebug in Firefox is the easiest way to find the ID of the <select> :)
Here's the test button I added to my page to check if the above code was working:
<script type="text/javascript">
function doFoo() {
// Change "myEditor" below to the ID of your TinyMCE instance.
var insertsElem = document.getElementById("myEditor_mylistbox");
insertsElem.options.length = 1; // Remove all but the first option.
var optElem = document.createElement("option");
optElem.value = "1";
optElem.text = "Foo";
insertsElem.add(optElem, null);
optElem = document.createElement("option");
optElem.value = "2";
optElem.text = "Bar";
insertsElem.add(optElem, null);
}
</script>
<button onclick="doFoo();">FOO</button>
Hope this helps, or at least gets you started.
Step 1 - Provide a JsonResult in your controller
public JsonResult GetInserts(int containerId)
{
//some code to get list of inserts here
List<string> somedata = doSomeStuff();
return Json(somedata);
}
Step 2 - Create javascript function to get Json results
function getInserts() {
var params = {};
params.containerId = $("#184").val();
$.getJSON("GetInserts", params, updateInserts);
};
updateInserts = function(data) {
var insertsElem = document.getElementById("183_mylistbox");
insertsElem.options.length = 1; // Remove all but the first option.
var optElem = document.createElement("option");
for (var item in data) {
optElem = document.createElement("option");
optElem.value = item;
optElem.text = data[item];
try {
insertsElem.add(optElem, null); // standards compliant browsers
}
catch(ex) {
insertsElem.add(optElem, item+1); // IE only (second paramater is the items position in the list)
}
}
};
Step 3 - Create NativeListBox (code above provided by ZoogieZork above)
var mlb = cm.createListBox('mylistbox', {
title: 'Inserts'
}, tinymce.ui.NativeListBox);
// Set our own change handler.
mlb.onPostRender.add(function(t) {
tinymce.dom.Event.add(t.id, 'change', function(e) {
var v = e.target.options[e.target.selectedIndex].value;
tinyMCE.activeEditor.execCommand("mceInsertContent", false, v);
e.target.selectedIndex = 0;
});
});
//populate inserts on listbox create
getInserts();

Resources