In my ASP.Net/MVC application, I am using AngularJS to display a list of records from the database. When I update a record, it doesn't get updated in the view (html) until I refresh the page?
The view:
<tr ng-repeat="bu in bus">
<td>{{bu.BU_Name}}</a></td>
<td>{{bu.BU_Info}}</a></td>
<th>Del</th>
</tr>
The JS:
$scope.editItem= function (bu) {
$http.post('/CO/DelBU', {dbunt: bu})
.then(function (response) {
$scope.bus = response.data;
})
.catch(function (e) {
console.log("error", e);
throw e;
})
.finally(function () {
console.log("This finally block");
});
};
The MVC controller:
[HttpPost]
public JsonResult DelBU(BUs dbunt)
{
var db = new scaleDBEntities();
var burecord = db.Buses.Find(dbunt.BU_ID);
db.Database.ExecuteSqlCommand("UPDATE dbo.BUs SET BU_Name='just a test'");
var burecords = db.Buses.ToList();
return Json(burecords, JsonRequestBehavior.AllowGet);
}
So, when I click on edit, the name doesn't change on the screen unless I refresh the page! How can I fix this?
Thank you
i think you need to setup a watch for bus - see here for more detail:
How do I use $scope.$watch and $scope.$apply in AngularJS?
Related
I have a cascading dropdown like for eg first dropdown shows the list of countries and based on the selection of countries the next dropdown gets populated. The problem is that in development environment it's working fine but when deployed in a server the first dropdown gets populated correctly as it's elements come from resource file and after selection of first drop down I get an error.
JS :
<script>
$(document).ready(function () {
$("#Site").change(function () {
var SelectedVal = $(this).val();
$("#Model").html('');
$("#Model").append($("<option></option>").attr("value", '')
.text(' '));
if (SelectedVal != '') {
$.get("/Home/GetModelList", { Sid: $("#Site").val() }, function (data) {
$("#Model").empty();
$("#Model").html('');
$("#Model").append($("<option></option>").attr("value", '')
.text(' '));
if (data.modelAlert != null) {
alert(data.projectAlert);
}
$.each(data.models, function (index, item) {
$("#Model").append($('<option></option>').text(item));
});
});
}
})
});
</script>
Controller :
public JsonResult GetModelList()
{
List<string> models = db.GetModels();
string modelAlert = alert.GetAlert();
var result = new { modelAlert, models };
return Json(result, JsonRequestBehavior.AllowGet);
}
The error message that I get is
Failed to load resource: the server responded with a status of 404 (Not Found) Home/GetModelList?Sid=Ind:1
I checked for similar problems like this and it was all about the JS path or the controller path but I've already given the absolute path. Can someone let me know where am I going wrong, let me know if any additional data is needed.
Thanks
$.get("/Home/GetModelList", { Sid: $("#Site").val() }, function (data) {
The above line was causing the routing problem, usually when we call a controller action from js in this way there tends to be a routing problem due to the folder structure reference. In order to avoid this routing problem and to be more clear we can also call controller action from js like below
$.get('#Url.Action("MethodName", "ControllerName")', function (data) {
This resolved my issue.
I am trying to mimic an mvc ActionLink. I want the whole row to be clickable. when the actionlink is clicked, it calls the connected controller and executes the code within. I want my Jquery/ajax call to do the same.
I've tried multiple ways of doing this with no luck. I'm currently at a point where the row is clickable and the Jquery sees that, however the ajax call does not execute. Or, if it does, the controller does not execute correctly
Here is the Jquery code that catches the click.
$(document).ready(function () {
$('#policyTable').on('click', '.clickable-row', function (event) {
$(this).addClass('primary').siblings().removeClass('primary');
var Id = $(this).closest('tr').children('td:first').text();
var url = "/Home/ReviewPolicy";
var uc = $(this).closest('tr').children('td:first').text();
alert("Does the click work? " + Id);
$.ajax({
type: "POST",
url: "/Home/ReviewPolicy",
dataType: 'text',
data: { Id: Id }
});
})
})
Here is the controller it is calling:
[HttpPost]
public ActionResult ReviewPolicy(string Id)
{
//Declare policyVM for individual policy
PolicyRenewalListVM model;
int val = Convert.ToInt32(Id);
using (Db db = new Db())
{
//Get the row
PolicyRenewalListDTO dto = db.RenewalPolicies.Find(val);
//confirm policy exists
if (dto == null)
{
return Content("This policy cannot be found.");
}
//initialize the PolicyRenewalListVM
model = new PolicyRenewalListVM(dto);
}
//return view with model
return View(model);
}
When the actionlink itself is clicked (It's not here in the code as I didn't see it being necessary for this problem) it fires and everything works as it should, but the jquery call, sending the very same value (Id) does not.
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
I am getting value in a dropdown list and I wanted to get the selected value in controller when user select any value from the dropdown list. My view is -
#using (Html.BeginForm("ApReport", "Sales", FormMethod.Post))
{
#Html.DropDownList("Ddl", null, "All", new { #class = "control-label"})
#Html.Hidden("rddl")
}
controller -
[HttpPost]
public ActionResult ApReport(ApReport Ddl)
{
string Ddlvalue = string.Empty;
if (Request.Form["rddl"] != null)
{
Ddlvalue = Request.Form["rddl"].ToString();
}
}
but I am not getting any value. Also, I donot want to use any submit button.
Thanks in advance
The use of Ajax allows you as the developer to update the main view without reloading the entire page, as well as send data to the server in the background.
This is how I would have accomplished this task.
Firstly, I would have created an action in my controller which returns a JsonResult. This will return a JSON object to your calling jquery code, that you can use to get values back into your views. Here is an example of the action method.
[HttpGet]
public JsonResult YourActionName(string selectedValue) //Assuming key in your dropdown is string
{
var result = DoYourCalculation(selectedValue);
return Json(new { myResult = result }, JsonRequestBehavior.AllowGet);
}
Now, you need to add your jquery code. I would recommend you place this in a seperate javascript file referenced by your view.
Here is the JQuery code, with the ajax call to the Action in your controller. The Ajax call to the server is initiated by the 'change' event of your DropDown, handled in JQuery, as can be seen below.
$(function () {
$(document)
.on('change', '#Ddl', function(){
var valueofDropDown = $(this).val();
var url = '/YourControllerName/YourActionName';
var dataToSend = { selectedValue: valueofDropDown }
$.ajax({
url: url,
data: dataToSend,
type: 'GET',
success: function (dataReceived) {
//update control on View
var receivedValue = dataReceived.myResult ;
$('YourControlIDToUpdate').val(receivedValue);
}
})
});
};
I have a datatable, on that datatable i set a Html.ActionLink. When I click that action link, I want to send an id of the item to a javascript function and have a new datatable appear below with all of its content that belongs to the selected item in the datatable above. So for example if I click a students name in a table, I want all the students Grades and Test to appear below in a separate datatable. I've never worked with javascript much so I'm not sure how I can do this. If someone can please point me in the right direction or give some tips I'd appreciate it.
original first datatable:
#foreach (var item in ((List<Epic>) ViewData["selectedestimate"]))
{
<tr>
<td>
#* #Html.ActionLink(#item.Name, "action", "controller", new {id = item})*#
#item.Name
</td>
Javascript to call:
<script type="text/javascript">
function StoryClick(story) {
$.get("#Url.Action("action", "controller")", function (response) {
$('#stories').accordion({ collapsible: true });
});
}
</script>
ActionController:
public List<EpicDetails> getEpicDetails(int id)
{
return eRepository.getItemsById(id).tolist();
}
Or do I need an ActionResult?
public Actionresult Details(int id)
{
}
I realize that I'm not even close right now, but its just b/c I'm not sure what steps to take to do this.
Eventually I would make a accordion and put the table in the accordion.
In situations like this I like to actually keep the <a> the ActionLink generates, and just add JavaScript to enhance the behavior of the link. So your view wouldn't really change (I did add a class so that we can bind an event handler to it later):
#Html.ActionLink(#item.Name, "action", "controller", new {id = item, #class = "item-link" })
Then write some jQuery (it looks like you already have a dependency on jQuery. If not, I can revise the answer to use vanilla JavaScript) to bind an event handler to links with class item-link:
<script type="text/javascript">
$(document).ready(function () {
$("a.item-link").click(function (event) {
event.preventDefault(); // Stop the browser from redirecting as it normally would
$.get(this.href, function (response) {
// Do whatever you want with the data.
});
});
});
</script>
And, yes, your action method in the controller should return an ActionResult. It's hard for me to say what type of ActionResult you should return without actually knowing what type of data you want to consume on the client, but if you wanted to inject HTML onto the page, you could write something like this:
public ActionResult Details(int id)
{
var itemDetails = /* Get details about the item */;
return PartialView("Details", itemDetails);
}
Then in your JavaScript you would write:
$("a.item-link").click(function (event) {
event.preventDefault(); // Stop the browser from redirecting as it normally would
$.get(this.href, function (response) {
$("element_to_populate").html(response);
});
});
Where element_to_populate would be a selector that points to where you want to inject the HTML.
I would highly recommend using javascript templating (I prefer handlebars.js) on the client side and returning your student data as a JsonResult. This will keep your bandwidth usage to a minimum.
But, because you seem more comfortable with razor, you could use that for all your templates, return plain html from your controller/view, and then use this javascript instead
<script type="text/javascript">
$(function() {
$("a.item-link").click(function (event) {
event.preventDefault(); // Stop the browser from redirecting as it normally would
$("#gradesContainer").load(this.href, function (response) {
//Do whatever you want, but load will already have filled up
//#gradesContainer with the html returned from your grades view
});
});
});
</script>
In your main page, below the student list, you would just need to add
<div id="gradesContainer"></div>
Your other controller would look like this
public ActionResult TestGrades(int id) {
var model = getTestGradesModel(id);
return View(model);
}
If you were returning JSON for client-side javascript templating it would look like
public ActionResult TestGrades(int id) {
var model = getTestGradesModel(id);
return new JsonResult() {Data = model}; //no view here!
}