I have an angular application, and I am trying to get a list of users from the server. I ran into an issue. I have page call CurrentUsers. If CurrentUsers method returns a Json Object, the entire object is display on the page regardless of what I do in the app controller and html page. If the method return a view, it does not display anything. However, I can hard code the json object in the cotroller, and it will work fine.
As a result, I created another method to return the json object. I made a call to that method, but it never reached the server. Your help will be very much appreciated.
The CurrentUsers Method returning a JSON Object, the entire json object display on the screen regardless
[HttpGet]
public JsonResult CurrentUsers()
{
List<Users> currentUser = new List<Users>()
{
new Users{ UserName = "JDoe", Professor="SSmith", Course = "English1"},
new Users{ UserName = "ADan", Professor="SDhor", Course = "Science"},
new Users{ UserName = "ADes", Professor="SCarry", Course = "Religion101"},
new Users{ UserName = "DJay", Professor="SCrowe", Course = "Teaching101"},
new Users{ UserName = "MAnne", Professor="TRow", Course = "PreCalc"},
};
return Json(new { Ok = true, data= currentUser });
// return View();
}
If the above method return a View, I can modify the controller as
shown below, and I will see the appropriate Information
Registration.controller('CurrentUsersController', function ($scope, $http) {
$scope.currentUsers = [{ "Professor": "SSmith", "UserName": "JDoe", "Course": "English1" }, { "Professor": "SDhor", "UserName": "ADan", "Course": "Science" }, { "Professor": "SCarry", "UserName": "ADes", "Course": "Religion101" }]
});
I modified the controller to use a service and created the method below to read the Current Users so that the view can simply return a View(). However, I have not been able to get the 'GET'to work.
[HttpGet]
public JsonResult GetUsers()
{
List<Users> currentUser = new List<Users>()
{
new Users{ UserName = "JDoe", Professor="SSmith", Course = "English1"},
new Users{ UserName = "ADan", Professor="SDhor", Course = "Science"},
new Users{ UserName = "ADes", Professor="SCarry", Course = "Religion101"},
new Users{ UserName = "DJay", Professor="SCrowe", Course = "Teaching101"},
new Users{ UserName = "MAnne", Professor="TRow", Course = "PreCalc"},
};
return Json(new { Ok = true, data = currentUser , message =
"Success"}, JsonRequestBehavior.AllowGet);
}
the modify CurrentUsers Method to return a view
public ActionResult CurrentUsers()
{
return View();
}
My modify controller
Registration.controller('CurrentUsersController', function ($scope, GetUSerService) {
$scope.message = 'this is the Current User controller';
$scope.currentUsers = [];
var result = GetUSerService.getData()
.then(function (result) {
console.log('the result');
console.log(result.data);
});
});
my service
Registration.service('GetUSerService', function ($http,$q) {
this.getData = function () {
var deferredObject = $q.defer();
$http.get('/Home/GetUsers').
success(function (data) {
console.log('service call data');
console.log(data);
deferredObject.resolve({ success: true, data : data.data });
}).
error(function () {
deferredObject.resolve({ success: false, data : '' });
});
return deferredObject.promise;
};
});
Updated 10/6 #5:50
#FernandoPinheiro answer works for me. The only thing is that the GetUsers action is being called twice.
Updated 10/7
I figured out why the post was being done twice. On my template, I had ng-app="Registration", and I had ng-controller= "CurrentUsersController". Because I specified the controller name in the route provider, I did not need it to add it to the partial view. As soon as I removed it from the view, it worked as expected.
Your GetUserService is calling $http.post('/Home/GetUsers') instead of $http.get('/Home/GetUsers').
Besides, shouldnt you set the Route attribute for the action ?
Related
I am totally new to Asp.Net Core and I am trying to implement an Inventory controlling system. Now I am facing a problem of saving sales data to database. The main problem is I have failed to bring data to controller. I have 'sales', 'SalesProducts' and 'products' tables in database. What I have tried so far,
Sales Create View has a dropdown to select products and it populates using SalesViewModel:
SalesViewModel
public class SalesViewModel
{
public Sale Sale { get; set; }
public List<SelectListItem> Products { get; set; }
}
To create sales items list, each time user select a product and it's quantity, 'subArray' will be created and that item array will be pushed to 'SalesItemArray',
$('.btn-sales-add').on('click', function () {
let subArray = [];
let productId = $('#product-id').val();
let productName = $('#product-id option:selected').text();
let price = $('#sales-price').val();
let quanity = $('#sales-quantity').val();
let subTotal = $('#sales-sub-total').val();
quanity = parseInt(quanity);
subTotal = parseFloat(subTotal);
total += subTotal;
$('#sales-total input').val(total);
subArray.push(productId);
subArray.push(productName);
subArray.push(price);
subArray.push(quanity);
subArray.push(subTotal);
salesItemsArray.push(subArray);
});
Array Format
[[pro_id, pro_name, quantity, subTotal],[pro_id, pro_name, quantity, subTotal]]
To bring the sales data and sales items to controller, I used FormData object and another FormDataViewModel as shown in this solution
SalesFormDataViewModel
public class SalesFormDataViewModel
{
public string StoreId { get; set; }
public string Total { get; set; }
public string[] SalesItemList { get; set; }
}
I am passing SalesViewModel to view and passing SalesFormDataViewModel to controller. I am posting the data using Ajax,
let storeId = $("#sales-store-id").val();
let total = $("#sales-total input").val();
let salesItemList = salesItemsArray;var
formData = new FormData();
formData.append("StoreId", storeId);
formData.append("Total", total);
formData.append("salesItemList", salesItemList);
$.ajax({
url: '/api/sales/createSales',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(formData),
success: function (response) {
alert('success');
},
error: function (response, error) {
alert('error');
}
});
The Controller
[HttpPost]
[Route("createSales")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> createSales(SalesFormDataViewModel
salesFormDataViewModel)
{
return Ok(new { success = "Stock updated successfully" });
}
Actually, I have tried almost every solutions searching the web but whatever tried, everytime I get same error response. I can not even reach to the breakpoint in controler because ajax throws an exception.
Ajax Response
Please, I am expecting all of your help. Thank you.
I am Editing this question to add more details. After trying Chens solution now getsthis error
I could not pass the array until I changed my viewModel. I had to remove the string array type to string type.
public class SalesFormDataViewModel
{
public string StoreId { get; set; }
public string Total { get; set; }
public string SalesItemList { get; set; }
}
Then, I appended the array to formData after converting the array to json string.
formData.append("SalesItemList", JSON.stringify(SalesItemList));
After searching through how to send formData to controller, before sending the formData object directly via ajax, I had to do following.
let dataObj = {};
formData.forEach((value, key) => {
dataObj[key] = value;
});
Then ajax call:
let jsonData = JSON.stringify(dataObj);
$.ajax({
url: '/api/Sales/createSales',
method: 'POST',
contentType: 'application/json',
data: jsonData,
processData: false,
cache: false,
success: function (response) {
alert("success");
},
error: function (response) {
alert("error");
}
});
This way I was able to paas two dimensional js array from view to controller. However with this I was unable to achieve save passed object to database since the SalesItemList array being received is a Json array, an exception Cannot deserialize the current JSON array, is thrown when trying to deserialze that array to object in sales controller. So, instead of passing an array of array, passing an array of object, same as above solved the issue.
let SalesItemList = [{},{}];
I am posting this answer thinking it would help those who face same problem and want to highlight that I am ended up with this solution thanks to those who reply to this question.
The 400 response is due to you not passing ValidateAntiForgeryToken.It is easy to forget about the anti-forgery token when crafting a POST request made with AJAX. If you omit the value from the request, the server will return a 400 Bad Request result. Please check if you are passing the correct Token.
Method one:
Add headers manually:
$.ajax({
//...
headers: { "RequestVerificationToken": yourtoken },
//...
});
For more detail, you can refer to this link.
Method two:
Comment out ValidateAntiForgeryToken:
//[ValidateAntiForgeryToken]
Edit:
Let's troubleshoot your mistakes step by step:
View:
Assuming the formData you got is correct, it should be something like this(Pay attention to several properties of ajax):
<script>
function Test()
{
let storeId = 1;
let total = "Total";
let salesItemList = [[1, "Name1", "quantity1", "subTotal1"], [2, "Name2", "quantity2", "subTotal2"]];
var formData = new FormData();
formData.append("StoreId", storeId);
formData.append("Total", total);
formData.append("salesItemList", salesItemList);
$.ajax({
url: '/createSales',
method: 'POST',
data: formData,
processData: false,
contentType: false,
cache: false,
async: false,
success: function (response) {
alert('success');
},
error: function (response, error) {
alert('error');
}
});
}
</script>
Controller:
[HttpPost]
[Route("createSales")]
public async Task<IActionResult> createSales(SalesFormDataViewModel
salesFormDataViewModel)
{
return Ok(new { success = "Stock updated successfully" });
}
Im retrieving data in database using ajax but when I'm calling the method in controller I getting an error in JsonConvert.SerializeObject(model, Formatting.Indented, new JsonSerializerSettings and I don't know why. Here's my code:
Views
function EditRecord(Id) {
var url = "/Admin/GetCategoryGroupById?Id=" + Id;
$("#ModalTitle").html("Update Category Group");
$("#MyModal").modal();
$.ajax({
type: "GET",
url: url,
success: function (data) {
var obj = JSON.parse(data);
$("#Id").val(obj.Id);
$("#Name").val(obj.Name);
//$("#Status option:selected").text(obj.tblDepartment.DepartmentName);
$("#cbStatus").val(obj.Status);
}, error: function (xhr, status, error) {
alert(error);
}
})
}
Controllers
public JsonResult GetCategoryGroupById(int Id)
{
CategoryGroup model = db.CategoryGroups.Where(x => x.Id == Id).SingleOrDefault();
string value = string.Empty;
value = JsonConvert.SerializeObject(model, Formatting.Indented, new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
return Json(value, JsonRequestBehavior.AllowGet);
}
The error:
Please help me. Thank you.
i think that your db doesn't have any CategoryGroups with the specified id. this is why the singleOrDefault returns null. so you need to add an if statement to check weather model is null
I'm trying make an application with Ionic framework which can take and send data to MS SQL server. For this I am using web api. I have no problem with taking data but something wrong with send new datas. Here is my ionic code :
angular.module('starter.controllers',[])
.controller('CheckListCtrl', function($scope, ChecklistService, $ionicPopup) {
function addCheck(){
ChecklistService.addCheck()
}
.factory('ChecklistService', ['$http', function ($scope, $http) {
var urlBase = 'http://localhost:56401/api';
var CityService = {};
CityService.addCheck = function(){
var url = urlBase + "/TBLCHECKLISTs"
var checkdata = {
AKTIF : true,
SIL : false,
KAYITTARIHI : Date.now(),
KULLANICIID : 3,
BASLIK : "Onur",
TAMAMLANDI : false,
TAMAMLANMATARIHI : null,
GUN : 1
}
var request = $http({
method: 'POST',
url: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: checkdata
});
return request;
}
return CityService;
}]);
And here is my web api:
[HttpPost]
[ResponseType(typeof(TBLCHECKLIST))]
public IHttpActionResult PostTBLCHECKLIST(TBLCHECKLIST tBLCHECKLIST)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
tBLCHECKLIST.KAYITTARIHI = DateTime.Now;
db.TBLCHECKLISTs.Add(tBLCHECKLIST);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = tBLCHECKLIST.TABLEID }, tBLCHECKLIST);
}
When i try to send i get this exception:
After, I realize that I take that exception because my checkdata is never come to web api. I don't know why.
These are not the datas I send:
I have tried different versions of post request but nothing. When I try to send data with PostMan, it works and I can insert data to my database. But why I can't do it with my application? Can anybody help me?
I think this should be the problem:
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
Try this:
return $http.post(url, checkdata);
And in your API:
[HttpPost]
[ResponseType(typeof(TBLCHECKLIST))]
public IHttpActionResult PostTBLCHECKLIST([FromBody]TBLCHECKLIST tBLCHECKLIST)
{
//code here
}
Also, make sure your checkdata properties match the ones in your TBLCHECKLIST c# type.
I just got done with the rough draft of my app, and thought it was time to remove autopublish and insecure mode. I started transfering all the stray update and insert methods I had been calling on the client to methods. But now I'm having trouble returning a username from an ID.
My function before: (that worked, until I removed autopublish)
challenger: function() {
var postId = Session.get('activePost');
var post = Posts.findOne(postId);
if (post.challenger !== null) {
var challenger = Meteor.users.findOne(post.challenger);
return challenger.username;
}
return false;
}
Now what I'm trying:
Template.lobby.helpers({
challenger: function() {
var postId = Session.get('activePost');
var post = Posts.findOne(postId);
if (post.challenger !== null) {
var userId = post.challenger;
Meteor.call('getUsername', userId, function (err, result) {
if (err) {
console.log(err);
}
return result;
});
}
return false;
},
Using:
Meteor.methods({
getUsername: function(userId) {
var user = Meteor.users.findOne({_id: userId});
var username = user.username;
return username;
},
...
})
I have tried blocking the code, returning values only once they're defined, and console.logging in the call-callback (which returned the correct username to console, but the view remained unchanged)
Hoping someone can find the obvious mistake I'm making, because I've tried for 3 hours now and I can't figure out why the value would be returned in console but not returned to the template.
Helpers need to run synchronously and should not have any side effects. Instead of calling a method to retrieve the user, you should ensure the user(s) you need for that route/template are published. For example your router could wait on subscriptions for both the active post and the post's challenger. Once the client has the necessary documents, you can revert to your original code.
Is there any way to make a synchronous call with AngularJS?
The AngularJS documentation is not very explicit or extensive for figuring out some basic stuff.
ON A SERVICE:
myService.getByID = function (id) {
var retval = null;
$http({
url: "/CO/api/products/" + id,
method: "GET"
}).success(function (data, status, headers, config) {
retval = data.Data;
});
return retval;
}
Not currently. If you look at the source code (from this point in time Oct 2012), you'll see that the call to XHR open is actually hard-coded to be asynchronous (the third parameter is true):
xhr.open(method, url, true);
You'd need to write your own service that did synchronous calls. Generally that's not something you'll usually want to do because of the nature of JavaScript execution you'll end up blocking everything else.
... but.. if blocking everything else is actually desired, maybe you should look into promises and the $q service. It allows you to wait until a set of asynchronous actions are done, and then execute something once they're all complete. I don't know what your use case is, but that might be worth a look.
Outside of that, if you're going to roll your own, more information about how to make synchronous and asynchronous ajax calls can be found here.
I hope that is helpful.
I have worked with a factory integrated with google maps autocomplete and promises made, I hope you serve.
http://jsfiddle.net/the_pianist2/vL9nkfe3/1/
you only need to replace the autocompleteService by this request with $ http incuida being before the factory.
app.factory('Autocomplete', function($q, $http) {
and $ http request with
var deferred = $q.defer();
$http.get('urlExample').
success(function(data, status, headers, config) {
deferred.resolve(data);
}).
error(function(data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
<div ng-app="myApp">
<div ng-controller="myController">
<input type="text" ng-model="search"></input>
<div class="bs-example">
<table class="table" >
<thead>
<tr>
<th>#</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="direction in directions">
<td>{{$index}}</td>
<td>{{direction.description}}</td>
</tr>
</tbody>
</table>
</div>
'use strict';
var app = angular.module('myApp', []);
app.factory('Autocomplete', function($q) {
var get = function(search) {
var deferred = $q.defer();
var autocompleteService = new google.maps.places.AutocompleteService();
autocompleteService.getPlacePredictions({
input: search,
types: ['geocode'],
componentRestrictions: {
country: 'ES'
}
}, function(predictions, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
deferred.resolve(predictions);
} else {
deferred.reject(status);
}
});
return deferred.promise;
};
return {
get: get
};
});
app.controller('myController', function($scope, Autocomplete) {
$scope.$watch('search', function(newValue, oldValue) {
var promesa = Autocomplete.get(newValue);
promesa.then(function(value) {
$scope.directions = value;
}, function(reason) {
$scope.error = reason;
});
});
});
the question itself is to be made on:
deferred.resolve(varResult);
when you have done well and the request:
deferred.reject(error);
when there is an error, and then:
return deferred.promise;
var EmployeeController = ["$scope", "EmployeeService",
function ($scope, EmployeeService) {
$scope.Employee = {};
$scope.Save = function (Employee) {
if ($scope.EmployeeForm.$valid) {
EmployeeService
.Save(Employee)
.then(function (response) {
if (response.HasError) {
$scope.HasError = response.HasError;
$scope.ErrorMessage = response.ResponseMessage;
} else {
}
})
.catch(function (response) {
});
}
}
}]
var EmployeeService = ["$http", "$q",
function ($http, $q) {
var self = this;
self.Save = function (employee) {
var deferred = $q.defer();
$http
.post("/api/EmployeeApi/Create", angular.toJson(employee))
.success(function (response, status, headers, config) {
deferred.resolve(response, status, headers, config);
})
.error(function (response, status, headers, config) {
deferred.reject(response, status, headers, config);
});
return deferred.promise;
};
I recently ran into a situation where I wanted to make to $http calls triggered by a page reload. The solution I went with:
Encapsulate the two calls into functions
Pass the second $http call as a callback into the second function
Call the second function in apon .success
Here's a way you can do it asynchronously and manage things like you would normally.
Everything is still shared. You get a reference to the object that you want updated. Whenever you update that in your service, it gets updated globally without having to watch or return a promise.
This is really nice because you can update the underlying object from within the service without ever having to rebind. Using Angular the way it's meant to be used.
I think it's probably a bad idea to make $http.get/post synchronous. You'll get a noticeable delay in the script.
app.factory('AssessmentSettingsService', ['$http', function($http) {
//assessment is what I want to keep updating
var settings = { assessment: null };
return {
getSettings: function () {
//return settings so I can keep updating assessment and the
//reference to settings will stay in tact
return settings;
},
updateAssessment: function () {
$http.get('/assessment/api/get/' + scan.assessmentId).success(function(response) {
//I don't have to return a thing. I just set the object.
settings.assessment = response;
});
}
};
}]);
...
controller: ['$scope', '$http', 'AssessmentSettingsService', function ($scope, as) {
$scope.settings = as.getSettings();
//Look. I can even update after I've already grabbed the object
as.updateAssessment();
And somewhere in a view:
<h1>{{settings.assessment.title}}</h1>
Since sync XHR is being deprecated, it's best not to rely on that. If you need to do a sync POST request, you can use the following helpers inside of a service to simulate a form post.
It works by creating a form with hidden inputs which is posted to the specified URL.
//Helper to create a hidden input
function createInput(name, value) {
return angular
.element('<input/>')
.attr('type', 'hidden')
.attr('name', name)
.val(value);
}
//Post data
function post(url, data, params) {
//Ensure data and params are an object
data = data || {};
params = params || {};
//Serialize params
const serialized = $httpParamSerializer(params);
const query = serialized ? `?${serialized}` : '';
//Create form
const $form = angular
.element('<form/>')
.attr('action', `${url}${query}`)
.attr('enctype', 'application/x-www-form-urlencoded')
.attr('method', 'post');
//Create hidden input data
for (const key in data) {
if (data.hasOwnProperty(key)) {
const value = data[key];
if (Array.isArray(value)) {
for (const val of value) {
const $input = createInput(`${key}[]`, val);
$form.append($input);
}
}
else {
const $input = createInput(key, value);
$form.append($input);
}
}
}
//Append form to body and submit
angular.element(document).find('body').append($form);
$form[0].submit();
$form.remove();
}
Modify as required for your needs.
What about wrapping your call in a Promise.all() method i.e.
Promise.all([$http.get(url).then(function(result){....}, function(error){....}])
According to MDN
Promise.all waits for all fulfillments (or the first rejection)