Browser crashed when angularjs supply data on HTML datalist - javascript

I have a html datalist that supplies list of account name which around 14k+, it works fine but any browser that I used will not respond first then successfully supplied the data in datalist using ng-repeat. In worst case the browser crashed.
C# backend
public JsonResult getCollateralAccount() {
List<collateralAccount> accountlist = new List<collateralAccount>();
sqlHelper = new QueryHelper();
SqlParameter[] parameterList = { };
var table = sqlHelper.ExecuteQuery("collateralGetListOfAccount", System.Data.CommandType.StoredProcedure, parameterList).Tables[0];
accountlist = table.AsEnumerable().Select(row => new collateralAccount
{
Id = row.Field<int>("Id"),
name = row.Field<string>("name")
}).ToList();
return new JsonResult { Data = accountlist, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
Service
getCollateralAccount: function (data) {
var $getCollateralAccount = $http.get('/Collatera/getCollateralAccount').
success(function (data) {
return data;
});
return $getCollateralAccount;
}
Controller
$scope.listofCAccount = [];
CollateralService.getCollateralAccount().then(function(msg){
if(msg.data.length>0){
$scope.listofCAccount = msg.data;
}
});
View
<input id="username" type="text" class="form-control width100" list="UsersName" ng-model="user.name" required/>
<datalist id="UsersName">
<option ng-repeat="acc in accListContainer track by $index" value="{{acc.name}}" data-val="{{acc.name}}"></option>
</datalist>
Can anyone help me how to stop my browser from crashing or not responding?

success/error has been deprecated, also you are using then at your controller, so just change your service as below(return Promise of $http.get directly).
getCollateralAccount: function (data) {
return $http.get('/Collatera/getCollateralAccount');
}

14K result in an ng-repeat is for sure not what any user would like to see.
You could try limitTo filter if this applies to you. You can use it like this:
ng-repeat="acc in accListContainer | limitTo:10 track by $index"
For more interesting approaches see: How to improve performance of ngRepeat over a huge dataset (angular.js)?

Related

angularjs: how to store the function returning value in one variable . based on ng-repeat

hi i am getting the intrestedid from ng-repeat , i want to call another service and store that data in one variable dynamically , because need send seperate api for getting images.
my html is look like this
<div class="" ng-repeat="item in items" >
<div ng-init="MyPic = getMyprofile(item.interestedTo)">
<img src="{{MyPic}}">
</div>
</div>
My controller is look like this.
$scope.getMyprofile = function(IntrstdId){
appServices.profile( IntrstdId, function(response){
$scope.meDetails = response.data;
})
return $scope.meDetails;
}
My services is look like this.
service.profile= function(userId, callback) {
path = serviceUrl + '/profile/'+ userId;
$http({
method: 'GET',
url: path
}).then(function(data) {
callback(data)
}, function(data) {});
}
but its getting undefined , any issues in this code.
I tried to resolve this by creating some abstract stub, that may be helpful to you. Please review and let me know if issue still arise
HTML
<div ng-repeat ="data_ in parentData track by $index">
<ul>
<li ng-repeat="result in data_.data track by $index" ng-init="counter=increaseCounter();">
<div ng-model="counter"></div>
</ul>
</div>
Controller
// It simply store variable value in scope.counter
$scope.counter = 0;
$scope.increaseCounter = function () {
var cnt = $scope.counter++;
return cnt;
};
//Another way is to call service while update variable vaule
$scope.counter = 0;
$scope.increaseCounter = function () {
var cnt = $scope.counter++;
AppService.updateValue(cnt);
return cnt;
};
$scope.getMyprofile = function(IntrstdId){
appServices.profile( IntrstdId, function(response){
$scope.meDetails = response.data;
})
return $scope.meDetails;
}
I think issue is this function. appService.profile is asyncronize method and before complete it function return $scope.meDetails;
my suggestion is to hardcore some value like in below and see the result. if it is working then you have to change the function accordingly.
$scope.meDetails ='some value';
return $scope.meDetails;
There are several best practice issue along with the async problem.
1.Avoid using ng-init unless you want to re-run the function when you reconstruct the element, for instance ng-if. It is more so when you use ng-repeat without track by, any changes in the data source would re-trigger all ng-init in the children.
Solution: Run them when you init the controller, or as soon as $scope.items is filled.
angular.forEach($scope.items, function(item) {
appServices.profile(item).then(function(data){
item.myPic = data;
});
});
<div class="" ng-repeat="item in items" >
<img src="{{item.myPic}}">
</div>
2.The correct way to wrap a function that returns promise (which $http is) is to return the function itself. You can research more on how to pass the resolved/rejected result around.
// not needed anymore, just to showcase
$scope.getMyprofile = function(IntrstdId){
return appServices.profile( IntrstdId );
}
// same goes with the service function
service.profile= function(userId) {
path = serviceUrl + '/profile/'+ userId;
return $http({
method: 'GET',
url: path
}).then(function(response) {
return response.data;
});
}

Ajax request for asp.net mvc controller returning 500 - internal server error

I have these two selects on a view:
<select class="input-sm form-control input-s-sm inline" onchange="carregarCidades()" id="comboEstado">
...
</select>
<select class="input-sm form-control input-s-sm inline" id="comboCidade">
...
</select>
The first represents a State, and when I select it I want to execute the carregarCidades function to load the cities of that stat and them load them in the other select. Here is the function:
function carregarCidades() {
var url = "#Url.Action("CarregarCidades", "Usuario")";
var estado = $("#comboEstado").find(":selected").text();
$.get(url, { pEstado: estado }, function (cidades) {
$("#comboCidade").html(""); // clear before appending new list
$.each(cidade, function (i, cidade) {
$("#comboCidade").append(
$('<option></option>').val(cidade.id_cidade).html(cidade.cidade));
});
});
}
Now, here is the CarregarCidades action in the UsuarioController:
public ActionResult CarregarCidades(string pEstado)
{
string cCidades = oVFP.BuscaCidade(pEstado);
DataSet dsC = new DataSet();
dsC.ReadXml(new StringReader(cCidades));
JsonResult result = Json(dsC.Tables["curretorno"]);
return result;
}
I'm debugging the action and apparently everything is ok:
But, after the Action returns the Json result, the callback funcion is not called on the jquery code and I got a 500 internal server error in my console.
You have to JsonAllowRequestbehavior parameter to AllowGet, by default it is DenyGet :
JsonResult result = Json(dsC.Tables["curretorno"],JsonRequestBehavior.AllowGet);
You can read about Why it is needed on this post.
I would first make sure your method has the [WebMethod] attribute above its declaration.
The second thing I would suggest is returning your Json like this:
return Json(result, JsonRequestBehavior.AllowGet);
Generally it is one of or both of these issues that gives you a 500 error.
Edit:
Declaring it as a [WebMethod] may not be necessary.

AngularJS $service method invocation

I am a core java developer, now begining to learn AngularJS.
I am going through the tutorial pages and got the below doubt.
On of the example is
index.html
<div ng-app="invoice3" ng-controller="InvoiceController as invoice">
<b>Invoice:</b>
<div>
Quantity: <input type="number" min="0" ng-model="invoice.qty" required >
</div>
<div>
Costs: <input type="number" min="0" ng-model="invoice.cost" required >
<select ng-model="invoice.inCurr">
<option ng-repeat="c in invoice.currencies">{{c}}</option>
</select>
</div>
<div>
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
invoice3.js
angular.module('invoice3', ['finance3'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = currencyConverter.currencies;
this.total = function total(outCurr) {
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
};
this.pay = function pay() {
window.alert("Thanks!");
};
}]);
finance3.js
angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
var YAHOO_FINANCE_URL_PATTERN =
'//query.yahooapis.com/v1/public/yql?q=select * from '+
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&'+
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK';
var currencies = ['USD', 'EUR', 'CNY'];
var usdToForeignRates = {};
var convert = function (amount, inCurr, outCurr) {
return amount * usdToForeignRates[outCurr] / usdToForeignRates[inCurr];
};
var refresh = function() {
var url = YAHOO_FINANCE_URL_PATTERN.
replace('PAIRS', 'USD' + currencies.join('","USD'));
return $http.jsonp(url).success(function(data) {
var newUsdToForeignRates = {};
angular.forEach(data.query.results.rate, function(rate) {
var currency = rate.id.substring(3,6);
newUsdToForeignRates[currency] = window.parseFloat(rate.Rate);
});
usdToForeignRates = newUsdToForeignRates;
});
};
refresh();
return {
currencies: currencies,
convert: convert,
refresh: refresh
};
}]);
In finance3.js, I am not clear when refresh() method will be called.
There is a call refresh() inside the function($http) of 'currencyConverter' service . But when this statement will be invoked ?
All I see is we invoke convert() from InvoiceController. But no calls to refresh method.
in your code 'finance3' is not a name of you ng-app in your html code for this reason i dont understand your code. for mora information about implementation of factory and his use I recommend you read this guide carefully Angular Style Guide is a very good guide with examples of code.
and i recommend implement the refresh in your controller.
greetings D
The thinking here is that we need to get some external currency data when the service is created AND we also want the possibility of being able to refresh this data at some later point in the application.
Then it makes sense to make a function refresh which we'll call once when the service is first invoked, as you noticed by calling refresh(). We then expose the refresh function as a service method, so any user of the service can request that the service update it's data.
AngularJS service/factory works same way as Java Singleton. So when your controller is initialized - code inside
angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
Will be executed. It defines currencies array and 2 functions. refresh() is called once. (You're probably supposed to launch it later when you need to update.)
Here is the Java analog of this service:
public class Finance3 {
public static Finance3 INSTANCE = new Finance3();
public String[] currencies;
public Map<String, String> usdToForeignRates;
private Finance3() {
refresh();
}
private void refresh() {
new Thread(new Runnable(public void run() {
usdToForeignRates = Http.get(...)
})).start();
}
}

AngularJS: TypeError: undefined is not a function with chained selects

I have two select boxes, options for one of the boxes are loaded right away, and the second (child) select will get its options from a callback that queries an API. It is not an option to pre-load all possible options because there are 4200 records that would be loaded without the parent's selected value.
When the ng-change event of the parent box fires, a call is made:
function CertificateSearchCtrl($q, CPSIAService) {
var vm = this;
vm.products = [];
vm.categories = [];
vm.certficate = {};
vm.categoryselect = {};
vm.productselect = {};
I can call this via ng-init, or directly in the controller on first load
vm.loadCategories = function() {
CPSIAService.getCategories().then(function(results){
vm.categories = results;
});
};
OR I can call this in the same fashion (ng-init or direct via controller)
vm.findProducts = function(data) {
CPSIAService.getProductsByCategory(data.id).then(function(results){
vm.products = results;
});
};
...
But I can't call the two together at all, either through ng-change or direct through controller forcing a category ID into the findProducts() call.
This should, in turn, allow the child select to be populated with the "products" array. The controlling html (which is output via a directive) is this:
<div class="small-12 medium-6">
<select ng-model="vm.categoryselect" ng-change="vm.findProducts(vm.categoryselect)" ng-options="categories.category for categories in vm.categories track by categories.id" ng-cloak>
<option value="">(choose a category)</option>
</select>
</div>
<div class="small-12 medium-6">
<select ng-model="vm.productselect" ng-change="vm.loadCertificate(vm.productselect)" ng-show="vm.products.length>0" ng-options="products.description for products in vm.products track by products.sku" ng-cloak>
<option value="">(select a product)</option>
</select>
</div>
Even if I try to load the options for the child select initially (rather than through the ng-change event) - I get the same error. Here is the Chrome stack trace:
TypeError: undefined is not a function
at render (angular.js:25905)
at Scope.$get.Scope.$digest (angular.js:14280)
at Scope.scopePrototype.$digest (hint.js:1468)
at Scope.$get.Scope.$apply (angular.js:14493)
at Scope.scopePrototype.$apply (hint.js:1478)
at HTMLSelectElement.selectionChanged (angular.js:25657)
at HTMLSelectElement.eventHandler (angular.js:3011)angular.js:11598 (anonymous function)angular.js:8548 $getangular.js:14282 $get.Scope.$digesthint.js:1468 scopePrototype.$digestangular.js:14493 $get.Scope.$applyhint.js:1478 scopePrototype.$applyangular.js:25657 selectionChangedangular.js:3011 eventHandler
Here is a sample of the JSON data in question. I've linted/validated it and it is fine.
[{"sku":"2004","description":"ADHSVE PAPR BLK BDR8CT-12"},{"sku":"2005","description":"ADHSVE PAPR BLU BDR8CT-12"},{"sku":"2006","description":"ADHSVE PAPR RED BDR8CT-12"},{"sku":"0043630-5987","description":"BORD 50 CS ASST 60 CT-1"},{"sku":"51671","description":"SLFSTK BORDER BLK 2X12-12"},{"sku":"51672","description":"SLFSTK BORDER BLU 2X12-12"},{"sku":"51673","description":"SLFSTK BORDER RED 2X12-12"}]
Help!
I have noticed that I can, in fact load my child select options only if I don't attempt to make two calls to my service at one time. Maybe I'm misunderstanding promises? I thought they resolve with the .then() function, but it errors out when I try to make the second one complete, even though the API call is fine and data does come back as expected (see JSON above)
JQuery does not affect the error - same reproduction with or without jQuery included.
found the solution guys. In my service, I had this:
function CPSIAService($q, Restangular) {
var deferred = $q.defer();
var CPSIAService = {};
CPSIAService.getProductsByCategory = function(params) {
//original call
// var response = Restangular.one('compliance/products/by/category',params);
var response = Restangular.one('products.json'); //params from category would go here
response.getList().then(function(data) {
deferred.resolve(data);
});
return deferred.promise;
};
CPSIAService.getCategories = function() {
//original call
//var response = Restangular.all('compliance/categories/all');
var response = Restangular.all('categories.json');
response.getList().then(function(data) {
deferred.resolve(data);
});
return deferred.promise;
};
return CPSIAService;
}
Specifically, notice this at the top of the service:
var deferred = $q.defer();
If I were to make a call to the service after initial page load, the error would occur because I wasn't deferring the promise in the actual function I was calling. The solution was to go from this:
CPSIAService.getProductsByCategory = function(params) {
var response = Restangular.one('compliance/products/by/category',params);
response.getList().then(function(data) {
deferred.resolve(data);
});
return deferred.promise;
};
to this:
CPSIAService.getProductsByCategory = function(params) {
var deferred = $q.defer(); //defer here because we're calling it from the ng-change event fire
var response = Restangular.one('compliance/products/by/category',params);
response.getList().then(function(data) {
deferred.resolve(data);
});
return deferred.promise;
};
And now it works like a charm.
Had the same problem and solution was to update angular-mocks.js to the matching version as per this answer.

How to Post multiple rows with AngularJS

I am trying to submit a form with multiple table rows. I have found examples online and have managed to send the table data to the AngularJS controller but I cannot figure out how to send that data to the apiController.
The form is a Purchase Order that has a table with the Purchase Order Details. I have chained the submit button with the both the Purchase Order and Purchase Order Detail submit functions.
<table class="table" style="">
<tbody>
<tr class="pointer no_selection" ng-repeat="newJobItem in rows">
<td style="width:50px"><input style="width:20px" type="checkbox" class="form-control"></td>
<td style="width:200px">{{newJobItem.JobItemName}}</td>
<td style="width:480px">{{newJobItem.JobItemDescription}}</td>
<td style="width:100px">{{newJobItem.JobItemMatSize}}</td>
<td style="width:150px">{{newJobItem.JobItemQuantity}}</td>
<td style="width:50px">{{newJobItem.JobItemUOM}}</td>
<td style="width:150px">${{newJobItem.JobItemPrice | number : fractionSize}}</td>
<td style="width:20px"><input type="button" value="X" class="btn btn-primary btn-sm" ng-click="removeRow(newJobItem.JobItemName)" /></td>
</tr>
</tbody>
</table>
<input style="margin-right:30px" id="btn-width" type="button" class="btn btn-default" ng-click="submitPurchaseOrder();submitPurchaseOrderDetail()" value="Submit"/>
Controller
//Post Purchase Order
$scope.PODate = new Date(); //Todays Date
$scope.POId = Math.floor(Math.random() * 1000000001) //PurchaseOrder Id Generator
$scope.submitPurchaseOrder = function () {;
var data = {
JobId: $scope.job.JobId,
POId : $scope.POId,
PONumber: $scope.currentItem.PONumber,
PODate: $scope.PODate,
POAmount: $scope.currentItem.POAmount,
POLastPrintDate: $scope.currentItem.POLastPrintDate,
POEmail: $scope.POEmail,
POPrint: $scope.currentItem.POPrint,
POFaxNumber: $scope.POFaxNumber,
PONotes: $scope.currentItem.PONotes,
POCreatedBy: $scope.currentItem.POCreatedBy,
PODeliveryDate: $scope.currentItem.PODeliveryDate,
POShipVia: $scope.currentItem.POShipVia,
POShowPrices: $scope.currentItem.POShowPrices,
POCostCode: $scope.currentItem.POCostCode,
POApprovedNumber: $scope.currentItem.POApprovedNumber,
POBackorder: $scope.currentItem.POBackorder,
}
$http.post('/api/apiPurchaseOrder/PostNewPurchaseOrder', data).success(function (data, status, headers) {
console.log(data);
var tmpCurrentItem = angular.copy($scope.currentItem);
$scope.purchaseOrderArray.push(tmpCurrentItem)
angular.copy({}, $scope.currentItem);
//hide modal window
$scope.openNewPurchaseOrderModal.then(function (m) {
m.modal('hide');
});
});
};
//Post Purchase Order Detail
$scope.newJobItem = {};
$scope.submitPurchaseOrderDetail = function () {
var index = 0;
$scope.rows.forEach(function (newJobItem) {
console.log('rows #' + (index++) + ': ' + JSON.stringify(newJobItem));
});
var data = {
POId: $scope.POId,
PODItem: $scope.newJobItem.JobItemName,
PODDescription: $scope.newJobItem.JobItemDescription,
PODNotes: $scope.PODNotes,
PODUOM: $scope.newJobItem.JobItemUOM,
PODPrice: $scope.newJobItem.JobItemPrice,
PODQuantity: $scope.newJobItem.JobItemQuantity,
PODAmount: $scope.PODAmount,
PODMatSize: $scope.newJobItem.JobItemMatSize,
PODSection: $scope.PODSection,
PODMultiplier: $scope.PODMultiplier,
PODBackOrder: $scope.PODBackOrder
}
$http.post('/api/apiPurchaseOrderDetail/PostNewPurchaseOrderDetail', data).success(function (data, status, headers) {
console.log(data); window.top.location.reload();
});
};
Purchase Order Detail ApiController
// POST api/<controller>
public async Task<IHttpActionResult> PostnewPurchaseOrderDetail([FromBody]PurchaseOrderDetail newPurchaseOrderDetail)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
using (var context = new ApplicationDbContext())
{
context.PurchaseOrderDetails.Add(newPurchaseOrderDetail);
await context.SaveChangesAsync();
return CreatedAtRoute("PurchaseOrderDetailApi", new { newPurchaseOrderDetail.PODId }, newPurchaseOrderDetail);
}
}
Update
Changed as suggested
// POST api/<controller>
public HttpResponseMessage PostNewPurchaseOrderDetail(int id, PurchaseOrderDetail newPurchaseOrderDetail)
{
ApplicationDbContext db = new ApplicationDbContext();
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
if (id != newPurchaseOrderDetail.PODId)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
db.Entry(newPurchaseOrderDetail).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
You are executing two functions, each making an asyncronous request:
ng-click="submitPurchaseOrder();submitPurchaseOrderDetail()"
This doesn't feel right - both requests are sent in parallel and none is waiting for the other. Do you really mean it?
I would either package and send all data in a single request (also better experience for the user), then let the server deal with un-packaging. Or, if one request needs to wait for another, chain the Promises returned by $http:
$http.post(...)
.then(function(){
return $http.post(...);
})
.success(...)
.fail(...);
or use $q.all(promises) instead.
EDIT.
Also a cleaner and more scalable approach is to use dedicated Angular Service to post your data, see e.g. example on Angular Homepage
I'm not sure about your approach, to me it would be better to join both requests, purchaseOrder and the detail into a single call, you can still separate the data as you may feel convenient.
calling both functions at the same time could have unexpected behaviors since both are running asynchronously you may find 'race conditions'.
try to send a single request and organize how you are going to post the information like
var data = {
JobId: $scope.job.JobId, //common data between the order and the detail
POId: $scope.POId,
Order:{
PONumber: $scope.currentItem.PONumber,
PODate: $scope.PODate,
POAmount: $scope.currentItem.POAmount,
POLastPrintDate: $scope.currentItem.POLastPrintDate,
POEmail: $scope.POEmail,
POPrint: $scope.currentItem.POPrint,
POFaxNumber: $scope.POFaxNumber,
PONotes: $scope.currentItem.PONotes,
POCreatedBy: $scope.currentItem.POCreatedBy,
PODeliveryDate: $scope.currentItem.PODeliveryDate,
POShipVia: $scope.currentItem.POShipVia,
POShowPrices: $scope.currentItem.POShowPrices,
POCostCode: $scope.currentItem.POCostCode,
POApprovedNumber: $scope.currentItem.POApprovedNumber,
POBackorder: $scope.currentItem.POBackorder,
},
Detail:{
PODItem: $scope.newJobItem.JobItemName,
PODDescription: $scope.newJobItem.JobItemDescription,
PODNotes: $scope.PODNotes,
PODUOM: $scope.newJobItem.JobItemUOM,
PODPrice: $scope.newJobItem.JobItemPrice,
PODQuantity: $scope.newJobItem.JobItemQuantity,
PODAmount: $scope.PODAmount,
PODMatSize: $scope.newJobItem.JobItemMatSize,
PODSection: $scope.PODSection,
PODMultiplier: $scope.PODMultiplier,
PODBackOrder: $scope.PODBackOrder
}
}
you'll need to map the purchase order and the detail to a single dto object in your api controller.
just as a sidenote, I'd recommend you to use a stronger unique identifier rather than using a random number.
I think the trouble is with you controller try using this and also can you please elaborate the trouble.Does your APIcontroller is never found by your controller ?
public class Oders : ApiController // in your controller class
{
public HttpResponseMessage Post(PurchaseOrderDetails newOrder)
{
//your code
}
}

Categories

Resources