How to resolve a not working cascading drop down - c#

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.

Related

executing mvc controller using either Jquery or Ajax call

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.

C# MVC Calling a method in different path using AJAX

I have a HomeController in my ASP.NET MVC application in folder "Controllers". My View is in: "View/Home/Index.cshtml" (look at my figure below).
I am using Ajax to get some json file every a few second. Problem is in Ajax URL, because I really don't know and didn't find, how to tell that property, that it has to go back a few folders and then find the HomeController.
My Solution looks like this:
Here is a method in my HomeController:
[HttpGet]
public ActionResult GetRandomFeed()
{
Item i = ss.getRandomFeed();
return Json(new { Source = i.Media.Source, Avatar = i.User.Avatar, Text = i.Text, Name = i.User.Name }, JsonRequestBehavior.AllowGet);
}
My AJAX in the View:
setInterval(function () {
$.ajax({
type: "GET",
url: '/HomeController.cs/GetRandomFeed', // Of course I have tried a lots of attempts in here
contentType: "application/json;", // Not sure about this
dataType: "json",
success: function (response) {
console.log("Success :)");
},
error: function() {
console.log("Error!");
}
});
}, 2000);
All I want to get that JSON file (or can be even an array of strings) and use it in my Success function. It is a simple Slide Show and JSON contains the URLs that I want to show in the page every X seconds (just changing source of an image that is in that JSON file).
I couldn't find anything like this. How to use that URL correctly OR found something similiar for WebForms but cannot use it in MVC.
Change your AJAX URL declaration to:
url: '/Home/GetRandomFeed'
Remove the .cs
Or you can also do, assuming this view is under your controller:
url: '#Url.Action("GetRandomFeed")'
In my experience, it doesn't seem enter the function is just because the JSON return from the controller doesn't include Status = "OK"
[HttpGet]
public ActionResult GetRandomFeed()
{
...
...
return Json(new
{
Status = "Ok", ...
}

How to display the returned refreshed list of items after deletion in AngularJS?

I am learning AngularJS and how to use it with ASP.NET Web API, and I am struggling right now with displaying the returned refreshed list of products after deleting one product by the manager. When he deletes a product successfully, the list of products will be updated immediately after that deletion.
The deletion function works well, but after doing the deletion, I got the following error message:
I tried to follow the answer mentioned in this question HERE, but it seems that the developer returns a status from the deletion function in the Web API which is totally different than my case.
Here's the code of ProductRepository class:
public List<T_Product> GetAllProducts()
{
var query = from product in db.T_Product
select product ;
return query.ToList();
}
public List<T_Product> DeleteProduct(int productId)
{
var pro = (from product in db.T_Product
where product .ProductId == productId
select product ).SingleOrDefault();
db.T_Product.DeleteObject(pro);
db.SaveChanges();
return GetAllProducts();
}
Here's the code of deletion function in Web API:
public HttpResponseMessage Delete(int id)
{
var products = productRepository.DeleteProduct(id);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, products);
return response;
}
And here the AngularJS Controller Code:
app.controller('productsController', [productsFactory', 'productFactory', function (productsFactory, productFactory) {
var vm = this;
vm.Products = productsFactory.query();
// callback for ng-click 'deleteProduct':
vm.deleteProduct = function (aId) {
productFactory.delete({ id: aId });
vm.Products = productsFactory.query();
};
}]);
And here's the AngularJS Service Code:
app.factory('productsFactory', function ($resource) {
return $resource('/api/products', {}, {
query: { method: 'GET', isArray: true },
create: { method: 'POST' }
})
});
app.factory('productFactory', function ($resource) {
return $resource('/api/products/:id', {}, {
show: { method: 'GET' },
update: { method: 'PUT', params: { id: '#id' } },
delete: { method: 'DELETE', params: { id: '#id' } }
})
});
I debugged and captured the network packet using F12 in the IE 9 and the code returns the updated list but it did not show in the page. Why?
So how can I display the returned updated list of products immediately after any successful deletion operation?
As far as I can tell, the problem is exactly the same as the question you linked. productFactory.delete({ id: aId }); is an asynchronous call, so it needs time to send data to the server and get data back. You should put the code you want to happen after the delete occurs inside the delete's callback function:
// callback for ng-click 'deleteProduct':
vm.deleteProduct = function (aId) {
productFactory.delete({ id: aId }, function() {
vm.Products = productsFactory.query();
});
};
This way you can be sure the query function will happen after the item is deleted on the server.
Ideally you shouldn't need to call .query() again, and would just delete the item locally. That way you wouldn't need to wait for another server request/response.
I think you should be setting the value of vm.Products in a callback - Angular is resolving the asynchronous value initially (so simply assigning productsFactory.query directly to the vm.Products does work when the controller is created, as all async operations are completed before rendering), but when it comes to refreshing it after delete that doesn't work - translating your code so it is all callback-happy:
app.controller('productsController', [productsFactory', 'productFactory', function (productsFactory, productFactory) {
var vm = this;
productsFactory.query(function (products) {
vm.Products = products;
});
// callback for ng-click 'deleteProduct':
vm.deleteProduct = function (aId) {
productFactory.delete({ id: aId }, function() {
productsFactory.query(function (products) {
vm.Products = products;
});
});
};
}]);
Setting the resource to accept an array response
delete: { method: 'DELETE', params: { id: '#id' }, isArray: true }
and either using the value from the callback
vm.deleteProduct = function (aId) {
productFactory.delete({ id: aId }, function(remainingProducts) {
vm.Products = remainingProducts;
});
};
or the promise from the resource method
vm.deleteProduct = function (aId) {
vm.Products = productFactory.delete({ id: aId });
};
should do the trick.
As others have mentioned, you would typically just delete the item locally once the delete call returns (that is, inside the callback). What I tend to do is removing the item instantly and then re-add it if something goes wrong (by providing a second error-callback). Keep in mind though that the list might have changed in the meantine (unless the UI is somehow 'locked' during the AJAX call).
As a side note: the productFactory is also concerned with products, so you might want to consider merging the two resources. Having an empty or no id will go to just the right server resource.

ASP.NET MVC: passing a complex viewmodel to controller

firs of all i searched for my question but couldnt find anything that helped me get any further.
i am trying to implement a view which allows me to set permissions for the current user.
As the data-structure i use following recursive class where each PermissionTree-Object references the sub-permissions (permissions are hierarchically structured in my application) :
public class PermissionTree
{
public Permission Node; //the permission object contains a field of type SqlHierarchyId if that is relevant
public bool HasPermission;
public IList<PermissionTree> Children;
//i cut out the constructors to keep it short ...
}
here is how the controller looks like:
//this is called to open the view
public ActionResult Permissions()
{
//pass the root element which contains all permission elements as children (recursion)
PermissionTree permissionTree = PopulateTree();//the fully populated permission-tree
return View(permissionTree);
}
//this is called when i submit the form
[HttpPost]
public ActionResult Permissions(PermissionTree model)
{
SetPermissions(model);
ViewData["PermissionsSaved"] = true;
return View(model);//return RedirectToAction("Index");
}
in am using a strongly typed view like this:
#model PermissionTree
//....
#using (Html.BeginForm("Permissions", "Permission", null, FormMethod.Post, new { #class = "stdform stdform2" }))
{
<input name="save" title="save2" class="k-button" type="submit" />
<div class="treeview">
//i am using the telerik kendoUI treeview
#(Html.Kendo().TreeView()
.Name("Permissions")
.Animation(true)
.ExpandAll(true)
.Checkboxes(checkboxes => checkboxes
.CheckChildren(true)
)
.BindTo(Model, mapping => mapping
.For<PermissionTree>(binding => binding
.Children(c => c.Children)
.ItemDataBound( (item, c) => {
item.Text = c.Node.PermissionName;
item.Checked = c.HasPermission;
})
)
)
)
ok, so when i click the button, i want my viewmodel to be sent to the controller action that is decorated with [HttpPost]. But when i debug the application, the received model does not really contain my data (it is not null though).
Does anyone know how i can achieve my goal and get the whole viewmodel?
best regards,
r3try
I think it's better to use a JSON post here ,then it's easy to prepare the object in the javascript side.
I don't know how your HTML looks like or the names of the elements you can easyly use javascript/Jquery to build the client side json object with similar names and slimier hierarchy/dataTypes just like in the PermissionTree class. And then use Ajax post to post as JSON
var PermissionTree={Node:{},HasPermission:false,Children:{}}
$.ajax({ data:PermissionTree
type: "POST",
url: 'YourController/Permissions',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
}
);
The important thing is you need to find a better way of going throuth the tree view and build the object in javascript.
as i cant get that to work i was trying a slightly different approach:
example for adding a node:
- press add button -> execute ajax call -> add the node in nhibernate -> call the view again with the new data (the new node included)
controller-action that is called by the ajax request:
[Authorize]
[HttpPost]
public ActionResult AddPermission(string parentPermissionName, string permissionName)
{
var pd = ServiceContext.PermissionService.permissionDao;
Permission parentPermission = pd.GetPermissionByName(parentPermissionName);
if (parentPermission == null) {
parentPermission = pd.GetRoot();
}
if (parentPermission != null && !string.IsNullOrEmpty(permissionName) && !pd.PermissionExists(permissionName))//only add with a name
{
pd.AddPermission(parentPermission, permissionName);
}
//refresh data
PermissionTree permissionTree = LoadTreeSQLHierarchy(null, false);//start at root
return View("Permissions", permissionTree);
}
Ajax Request in the View:
function addNode() {
//... get the data here
var addData = { parentPermissionName: selectedNodeName, permissionName: newNodeName };
$.ajax(
{
data: addData,
type: "POST",
url: '#Url.Action("AddPermission", "Permission")',
dataType: "json",
success: function (result) {
//$('.centercontent').html(response);//load to main div (?)
return false;
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status + ":" + thrownError);
return false;
}
}
);
return false;
}
But when i execute this i get an error stating that json.parse hit an invalid character (i get this error at the alert in the ajax's error function).
Judging from that message i would say that the problem is that i am returning html but the ajax call expects json or so...
But what is the correct way to just reload my view with the new data? Can i somehow tell the ajax call to not go back at all and just execute the called controller-method?

Problem on how to update the DOM but do a check on the data with the code-behind

This is with ASP.NET Web Forms .NET 2.0 -
I have a situation that I am not sure how to fulfill all the requirements. I need to update an img source on the page if selections are made from a drop down on the same page.
Basically, the drop downs are 'options' for the item. If a selection is made (i.e. color: red) then I would update the img for the product to something like (productID_red.jpeg) IF one exists.
The problem is I don't want to do post backs and refresh the page every time a selection is made - especially if I do a check to see if the image exists before I swap out the img src for that product and the file doesn't exist so I just refreshed the entire page for nothing.
QUESTION:
So I have easily thrown some javascript together that formulates a string of the image file name based on the options selected. My question is, what options do I have to do the following:
submit the constructed image name (i.e. productID_red_large.jpg) to some where that will verify the file exists either in C# or if it is even possible in the javascript. I also have to check for different possible file types (i.e. .png, .jpg...etc.).
not do a post back and refresh the entire page
Any suggestions?
submit the constructed image name
(i.e. productID_red_large.jpg) to some
where that will verify the file exists
either in C# or if it is even possible
in the javascript. I also have to
check for different possible file
types (i.e. .png, .jpg...etc.).
not do a post back and refresh the
entire page
If you wish to not post back to the page you will want to look at $.ajax() or $.post() (which is just short hand for $.ajax() with some default options)
To handle that request you could use a Generic Http Handler.
A simple outline could work like the following:
jQuery example for the post:
$("someButton").click(function () {
//Get the image name
var imageToCheck = $("#imgFileName").val();
//construct the data to send to the handler
var dataToSend = {
fileName: imageToCheck
};
$.post("/somePath/ValidateImage.ashx", dataToSend, function (data) {
if (data === "valid") {
//Do something
} else {
//Handle error
}
}, "html");
})
Then on your asp.net side you would create an http handler that will validate that request.
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var fileName = context.Request["fileName"];
var fullPath = Path.Combine("SomeLocalPath", fileName);
//Do something to validate the file
if (File.Exists(fullPath))
{
context.Response.Write("valid");
}
else
{
context.Response.Write("invalid");
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
Hope this helps, if I missed the mark at all on this let me know and I can revise.
We have an app of the same type, webforms .net 2, we do something similar with the following setup:
Using jQuery you can call a method in the page behind of the current page, for example, the following will trigger the AJAX call when the select box called selectBoxName changes, so your code work out the image name here and send it to the server.
$(document).ready(function () {
$('#selectBoxName').change(function (event) {
var image_name = 'calculated image name';
$.ajax({
type: "POST",
url: 'SomePage.aspx/CheckImageName',
data: "{'imageName': '" + image_name + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
alert(msg);
},
error: function (a, b, c) {
alert("The image could not be loaded.");
}
});
});
});
Where SomePage.aspx is the current page name, and image_name is filled with the name you have already worked out. You could replace the img src in the success and error messages, again using jQuery.
The code behind for that page would then have a method like the following, were you could just reutrn true/fase or the correct image path as a string if needed. You can even return more complex types/objects and it will automatically send back the proper JSON resposne.
[System.Web.Services.WebMethod(true)]
[System.Web.Script.Services.ScriptMethod(ResponseFormat = System.Web.Script.Services.ResponseFormat.Json)]
public static bool CheckImageName(string imageName)
{
/*
* Do some logic to check the file
if (file exists)
return true;
return false;
*/
}
As it is .net 2 app, you may need to install the AJAX Extensions:
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=ca9d90fa-e8c9-42e3-aa19-08e2c027f5d6&displaylang=en
Could you not use a normal ajax call to the physical path of the image and check if it returns a 404?
Like this:
http://stackoverflow.com/questions/333634/http-head-request-in-javascript-ajax
<script type="text/javascript">
function UrlExists(url) {
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
return http.status != 404;
}
function ConstructImage() {
var e = document.getElementById("opt");
var url = '[yourpath]/' + e.value + '.jpg';
if (!UrlExists(url)) {
alert('doesnt exists');
//do stuff if doesnt exist
} else {
alert('exists');
//change img if it does
}
}
</script>
<select id="opt" onchange="ConstructImage()">
<option value="red">Red</option>
<option value="blue">Blue</option>
<option value="green">Green</option>
</select>

Categories

Resources