Im very new to javascript,jquery and ajax. So I have a model:
namespace hiophop.Models
{
public class CarMake
{
public class Category
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
}
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public int CategoryID { get; set; }
}
}
}
I create a list from the classes and add to them in my controller while passing JSON to the view:
namespace hiophop.Controllers
{
public class CarController : Controller
{
List<Category> lstCat = new List<Category>()
{
new Category() { CategoryID = 1, CategoryName = "Dairy" },
new Category() { CategoryID = 2, CategoryName = "Meat" },
new Category() { CategoryID = 3, CategoryName = "Vegetable" }
};
List<Product> lstProd = new List<Product>()
{
new Product() { ProductID = 1, ProductName = "Cheese", CategoryID = 1 },
new Product() { ProductID = 2, ProductName = "Milk", CategoryID = 1 },
new Product() { ProductID = 3, ProductName = "Yogurt", CategoryID = 1 },
new Product() { ProductID = 4, ProductName = "Beef", CategoryID = 2 },
new Product() { ProductID = 5, ProductName = "Lamb", CategoryID = 2 },
new Product() { ProductID = 6, ProductName = "Pork", CategoryID = 2 },
new Product() { ProductID = 7, ProductName = "Broccoli", CategoryID = 3 },
new Product() { ProductID = 8, ProductName = "Cabbage", CategoryID = 3 },
new Product() { ProductID = 9, ProductName = "Pepper", CategoryID = 3 }
};
public ActionResult GetCategories()
{
return Json(lstCat, JsonRequestBehavior.AllowGet);
}
public ActionResult GetProducts(int intCatID)
{
var products = lstProd.Where(p => p.CategoryID == intCatID);
return Json(products, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string c ,string p)
{
ViewBag.x ="Product:"+ p;
ViewBag.y = "category" + c;
return View();
}
}
}
Here is were it gets confusing How do I retrieve the text value of the selected list box I am only able to retrieve the Int index for the CategoryId's. I want CategoryName ProductName both strings. Here is my view: The viewbags.x and y only return Ids. Ive tried a few things but Im stuck am I doing something wrong?I left some commented out for you to see what im trying.
#model hiophop.Models.CarMake
#{
ViewBag.Title = "CarView";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#*<h2>CarView</h2>*#
#ViewBag.y
#ViewBag.x
#using (Html.BeginForm("Index", "Car", FormMethod.Post))
{
<div>
<label for="category">Category</label>
<select id="category" name="c" class="form-control"></select>
<label for="product">Product</label>
<select id="product" name="p" class="form-control"></select>
<div id="result"></div>
<input type="submit" id="Button1" class="btn btn-default" />
</div>
}
#section scripts {
<script type="text/javascript">
$(document).ready(function () {
// Get a list of categories and a list of products of the first category.
$.getJSON('/Car/GetCategories', null, function (data) {
$.each(data, function () {
$('#category').append('<option value=' +
this.CategoryID + '>' + this.CategoryName + '</option>');
});
$.getJSON('/Car/GetProducts', { intCatID: $('#category').val() }, function (data) {
$.each(data, function () {
$('#product').append('<option value=' +
this.ProductID + '>' + this.ProductName + '</option>');
});
}).fail(function (jqXHR, textStatus, errorThrown) {
alert('Error getting products!');
});
}).fail(function (jqXHR, textStatus, errorThrown) {
alert('Error getting categories!');
});
// Dropdown list change event.
$('#category').change(function () {
$('#product option').remove();
$.getJSON('/Car/GetProducts', { intCatID: $('#category').val() }, function (data) {
$.each(data, function () {
$('#product').append('<option value=' +
this.ProductID + '>' + this.ProductName + '</option>');
});
}).fail(function (jqXHR, textStatus, errorThrown) {
alert('Error getting products!');
});
});
});
//var result = $('#result');
//$(document).ready(function () {
$("#Button").click(function () {
var request = $('#category option:selected').text() + "," + $('#product option:selected').text();
$.ajax({
type: 'POST',
contentType: "application/json;charset=utf-8",
url: '/Car/Index',
//data: "{'Category':'" + document.getElementById('#category') + "','food':'" + document.getElementById('#product') + " '}",
// async: false,
// success: function (response) {
// $('#category').val('');
// $('#product').val('');
// alert("record has been saved in database");
// },
// error: function () {
// console.log('there is some error');
// }
data: { c: request },
dataType: 'json',
success: function (data) {
result.html( '#category: ' + data.CategoryName + '' + '#product' + data.ProductName)
}
});
});
//});
</script>
}
Edit: Actually, as I look at your code more, and your description of the problem, I think your problem is even earlier. Your click even on the button isn't firing, because the ID should be Button1 and not Button, but the form is still submitting because your button is input type=submit, and you created the form with Html.BeginForm(). This causes the form to be submitted to the default action (the same as the get, but as a post instead... that's why it still hits the correct action) but the submitted variables are just the values of the inputs in the form. To get this working the way you intended, you need to alter the click event for the button (first so that the IDs match, or it will never fire), and then right at the beginning, prevent the normal form submission. So it should look like this:
$('#Button1').click(function(event) {
event.preventDefault();
// Do the rest of the click event handler here
});
End Edit
You're already getting the correct value with your jquery:
$('#category option:selected').text()
Would get the selected text for the #category dropdown, rather than the value. Your problem is that you're building the jquery object as a string and passing it back as the single parameter in your return. Instead, try this:
var postData = {
c: $('#category option:selected').text(),
p: $('#product option:selected').text()
};
then, in your ajax request:
data: postData
Also, for what it's worth, there's a much simpler shorthand for this type of ajax request:
$.post('/Car/Index', postData).done(function(data) {
//Do something with the server response here
result.html( '#category: ' + data.CategoryName + '' + '#product' + data.ProductName)
});
Note that success, error, and complete callbacks have been deprecated, and replaced by done(), fail(), and always() respectively.
Edit to address comment:
I'll answer your last question first... Yes!! in a browser (most modern browsers have some version of this) press the f12 key. This should open a developer tools window of some sort. Look for a tab with javascript stuff in it... in firefox, the tab is called debugger, in chrome it's called sources. I think it's called debugger in IE too, but I don't remember. Anyway, on this tab, find the page with your javascript code (if you do it all inline, which is what your example has, it will be the page named the same as your controller action, without an extension). this should bring up the 'view source' version of the page. You can set breakpoints in the javascript here, and when the browser gets to them it will break, and you can step through, over, or into just like you would in server side debugging in vs. You can also set a watch, and monitor the value of variables.
To send the data to the browser in your post, you want to send a JSON object which contains the data. JSON is just a series of key/value pairs, really. So a JSON object looks like this:
{ "key":"value" }
That is a very simple JSON object. If I were to store that in a variable (for example postData), like this:
var postData = { "key":"value" };
I could access the value for "key" by saying postData.key, and that would get me "value". In order to send the data to your controller action, you need to construct a JSON object which has properties that match the parameters that your controller action needs. In your example, you have two properties on your POST controller action: (string c, string p), So the JSON object you pass in needs to have a property (or KEY) named c, and one named p. Keep in mind that both javascript AND c# are case-sensitive, so your properties in your JSON object need to match exactly the names of the parameters your controller action wants.
So your controller action needs a JSON object which looks like this:
{ "c":"some value", "p":"some other value" }
Notice we separate the properties with a comma.. you can put any number in here. If your controller action has optional parameters, you can leave them out, but if not, they all need to be specified here, or you'll get a 404 error. So that object above is exactly what your controller wants to see, but the values aren't right obviously, we need to grab those from your select lists. So to do that, we use the jquery you already had, to get the text from the selected options, and we're left with this:
var postData = {
c: $('#category option:selected').text(),
p: $('#product option:selected').text()
};
Note that when specifying the name of the key, if it doesn't have spaces or anything weird in it, we can omit the quotes.
So now we have a properly formatted JSON object which matches what your controller action wants to receive. We just need to send this with an ajax post. Using the type of post you originally had, would look like this:
$.ajax({
type: 'POST',
//contentType: "application/json;charset=utf-8", This line is not necessary, the browser will figure it out
url: '/Car/Index',
data: postData,
//dataType: 'json', (This line is not necessary, the browser will figure it out
success: function (data) {
result.html( '#category: ' + data.CategoryName + '' + '#product' + data.ProductName)
}
});
Note that there are a couple of lines commented out. They are not necessary for this type of call, the browser is pretty good at figuring out what's needed.
Alternatively, I prefer a shorthand way of specifying posts like this, which I mentioned above, but i'll put it here again:
$.post('/Car/Index', postData).done(function(data) {
result.html( '#category: ' + data.CategoryName + '' + '#product' + data.ProductName)
});
This does exactly the same thing is the $.ajax version above, but it's much simpler, in my opinion.
I hope that clears it up! I'm happy to answer any more questions, or provide any additional clarification.
I have this pretty long script which is right now using a second AJAX call to fetch the data as a temporary Workaround.
Where there suggestion call is made /admin/locations/suggest.json the result is an array of objects. A list is displayed with the data from these objects. When one of them is clicked a second AJAX call is made to /admin/locations/view/' + locationId + '.json to fetch the location data - again. This data is already there but in the data that was returned from the first AJAX call.
My issue is now accessing the Locations variable from inside the on.click() code. I've already got the index there and everything but locations doesn't have the data present.
How can I populate the locations after my first call and use them in the on.click() event?
SuggestLocation = function() {
var locations = null;
$('#NewLocation').hide();
function suggestLocation(locations) {
$.ajax({
url: '/admin/locations/suggest.json',
type: 'POST',
data: $("#AgendaItemAdminAddForm, #AgendaItemAdminEditForm").serialize(),
success: function (data) {
var htmlString = '';
for (var p in data.data) {
htmlString = htmlString + '<li data-index="' + p + '" data-id="' + data.data[p].Location.id + '">' + data.data[p].Location.display_name + '</li>';
}
$('#LocationSuggestions').html(htmlString);
locations = data.data;
console.log(locations);
},
dataType: 'json'
});
};
$(document).on('click', '#LocationSuggestions li', function(event) {
locationIndex = ($(this).data('index'));
locationId = $(this).data('id');
$.ajax({
url: '/admin/locations/view/' + locationId + '.json',
type: 'GET',
data: null,
success: function(data) {
$('#SelectedLocation').html(
Mustache.render($('#LocationTemplate').html(), data.data)
);
},
dataType: 'json'
});
$('#AgendaItemLocationId').val(locationId);
$('#AgendaItemLocationId').val(locationId);
$('#LocationFormFields').hide();
$('#LocationSuggestions').html('');
$('#NewLocation').show();
});
$('#LocationFormFields input, #LocationFormFields textarea').keydown(function() {
suggestLocation();
});
$('#LocationFormFields select').change(function () {
suggestLocation();
});
$('#NewLocation').click(function(event) {
event.preventDefault();
$('#AgendaItemLocationId').val($(this).data(''));
$('#LocationFormFields').show();
$('#SelectedLocation').hide();
suggestLocation();
$(this).hide();
return false;
});
};
SuggestLocation();
Where you have:
var locations = null;
creates locations in the outer scope (the assignment of null is redundant, it does nothing useful), however when you do:
function suggestLocation(locations) {
that creates a locations variable that is local to suggestLocation, so later when you do:
locations = data.data;
the data is assigned to that locations variable, not the outer one. None of the calls to suggestLocation pass a parameter to the function, so simply get rid of locations as a formal parameter, i.e. make it:
function suggestLocation() {
so the value is assigned to the outer locations that is available to all functions within SuggestLocation.
Just remember that the AJAX call is asynchronous so make sure the callback has been called and the value assigned before you try to access it.
Also, function names starting with a capital letter are, by convention, reserved for constructors so SuggestLocation is not appropriate. Nor is it a good idea to have two functions whose name is identical except for the capitalisation of a single letter.
I am getting data from the server side using AJAX, I am now trying to populate data from from a list of objects into divs, the problem I am having is that I can not create the div while inside of the foreach loop.
$(document).ready(function () {
var divs = "";
var url = "../Graphs/CreateChart";
$.ajax({
type: 'POST',
url: url,
success: function (data) {
for (var i in data) {
var x = data[i];
for (var j in x) {
var val;
if (x.hasOwnProperty(j)) {
val = x[j].SpName;
if (x[j].SpName != "undefined") {
$('#a').appendTo('#content');
createBarChart("#a", "USP_Charts_BarChart1");
}
}
}
}
}, dataType: "json",
cache: false
});
});
</script>
I am trying to populate where it says "#a" with val and also then I need to populate the div I write with the val for the id, but when I try to put the document.write inside of the loop, I get a blank screen, any ideas why it would do this?
you're trying to append a created variable to your content? Try making the markup a string FIRST then appending it.
To test it try it without data.
$("<h2>HI</h2>").appendTo("#content");
If that works, then make a string that is the markup you want, with the data you need.
$("<a data='"+data.variable+"'></a>").appendTo("#content");
append and appendTo are VERY similar, but you need to use a string, not just an identifier, if the object doesn't exist yet.
am trying to update database.
For that iam doing like this
From js code
var data = {
"jobid": $('#jobid').val(),
"names": $('#names').val(),
"scripttype": $('#testscripts').val()
};
var msg="";
for(i = 1; i <=4; i++) {
data["Param" + i + "Key"] = $('#key' + i).val();
data["Param" + i + "Value"] = $('#value' + i).val();
}
$.ajax({
type: 'post',
url: "/save",
dataType: "json",
data: data
});
in node.js side
jobsCollection.update({
_id: id
}, {
$set: {
names: record.names,
script: record.scripttype,
// i dont know what should i place in this part???
// i have to set paramkey and paramValues
}
},
{
upsert: true
},
function (err, result) {
if (!err) return context.sendJson([], 404);
});
in record.names and record.scripttype getting proper values.
I don't know how to set values got from the for loop for updating
request going
Request: /save
{ jobid: '',
names: 'first',
scripttype: 'fow',
Param1Key: '1',
Param1Value: 'oneeeeee',
Param2Key: '2',
Param2Value: 'twoooooooo'
etc........
............
}
Since the property names are dynamic, you'll need to use the indexer-style property accessor of JavaScript as shown below.
Just reverse the process basically. I'm not sure where the data is located at the point you're calling update, so I called it sourceData in the example below;
// create an object with the well known-property names
var set = {
names : record.names,
script : record.scripttype
};
// now loop through the params and set each one individually
for(i = 1; i <=4; i++) {
var key = "Param" + i + "Key"; // build a key string
set[key] = sourceData[key]; // grab the data and set it
key = "Param" + i + "Value"; // and repeat
set[key] = sourceData[key];
}
then, pass it to your update:
jobsCollection.update({
_id: id
}, {
$set: set // pass the object created above
}, /* etc. */
If you don't know the count of Params, you could:
send it
use instead for .. in to loop through all the properties
For #2:
for(var key in sourceData) {
// you could filter the property names here if you'd like
// (like if only Params# were important)
set[key] = sourceData[key];
}
I want to create a list that consists of x number of objects that contains a name and a bool value
I want to create and send the list using ajax when this happens
This is in my Init
$('.si-accordion').click(function () {
$(this).siblings('.accordion_tab').toggleClass('IsExpanded');
SendSIInstance();
});
Here is the method it calls
function SendSIInstance() {
$('.si-accordion').hasClass('IsExpanded')
{
var NameValue = $('.si-accordion').text();
alert($('.si-accordion').text());
}
}
In my example I have 5 tabs (Which has the class si-accordion)
When I click them I toggle the class IsExpanded
I then want to create a list with objects like:
a String: text of si-accordion
A bool: if it has the class IsExpanded (if its there its true, else false)
The list with these 5 objects should then be send using AJAX so I can work with it.
You could do:
function SendSIInstance() {
var arrayToSend = [];
$('.si-accordion').each(function() {
var expanded = $(this).hasClass('IsExpanded');
var text = $(this).text();
var obj = {
expanded: expanded,
text: text
};
arrayToSend.push(obj);
});
//Send arrayToSend through ajax
$.ajax({
url: "yoururls",
data: arrayToSend,
success: function() {
// code to invoke after ajax call returns
}
});
}
Not sure if I understand your question, but try this...
var list = [$('.si-accordion').text(), $('.si-accordion').hasClass('IsExpanded') ...];
var xmlRequest = $.ajax({
url: "target.php",
data: list,
success: function() {
// code to invoke after ajax call returns
}
});