I have a global variable which I need to update after http get call. After update I need to pass this updated variable to other function. I can't understand what is the best way to do this. Here is my code:
app.controller('myCtrl', function($scope, $http) {
var data = '';
$http.get("data.json")
.then(function(response) {
data = response.data;
});
vm.mapOptions = {
controls: {
navigator: false
},
center: [40, -35],
zoom: 3,
layers: [{
style: {
fill: {
color: '#1996E4'
},
stroke: {
color: '#FFFFFF'
}
},
type: 'shape',
dataSource: data
}],
shapeCreated: onShapeCreated,
shapeFeatureCreated: onShapeFeatureCreated
};
});
Is it possible at all to update global variable after http call?
Thank you for help in advance.
When you do a http request, it takes some time to send the request and get the response, specially when you send the request to a API on a server,but in meanwhile the execution continues immediately and the statement after your http call is executed and if you have something that depends on the response, most properly will be failed.
in your case vm.mapOptions have dependency to data, which is a local variable getting the respnse from get request. so what can you do?
Step 1 :
make a function for all codes that are involve with your response :
$scope.myCallBack = function(data){
vm.mapOptions = {
controls: {
navigator: false
},
center: [40, -35],
zoom: 3,
layers: [{
style: {
fill: {
color: '#1996E4'
},
stroke: {
color: '#FFFFFF'
}
},
type: 'shape',
dataSource: data
}],
shapeCreated: onShapeCreated,
shapeFeatureCreated: onShapeFeatureCreated
};
}
Step 2 :
Call the myCallBack function inside your $http.get right after getting the response
var data = '';
$http.get("data.json")
.then(function(response) {
data = response.data;
$scope.myCallBack(data);
});
Related
I'm using Angular 6 and trying to implement a Chart.js line chart. Basically, I'm calling my API for two arrays: a weight_data array and a weight_date array and using them for the chart.
I store the arrays I got from the API request in two instances: this.weight_date and this.weight_data.
Here's the code for the chart:
// code for chart here
this.chart = new Chart(this.chartRef.nativeElement, {
type: 'line',
data: {
labels: this.weight_date, // your labels array
datasets: [
{
data: this.weight_data, // your data array
borderColor: '#e0573a',
fill: true
}
]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
display: true
}],
yAxes: [{
display: true
}],
},
title: {
display: true,
text: 'Weight Tracker',
fontFamily: "'Montserrat', sans-serif",
fontColor: '#272727',
fontSize: 18,
padding: 12
},
layout: {
padding: {
left: 10,
right: 20,
top: 0,
bottom: 0
}
},
gridLines: {
drawOnChartArea: true
},
}
});
It's works okay when I use pre-coded arrays (["11/02/18", "11/03/18", "11/04/18"] for dates and [65, 66, 67] for weight). But when I try to use the two instances, the chart comes up blank. There's no error of sorts, it's just blank.
I'm doing the API call first then initializing the chart, respectively, in ngOnInit. What am I missing here?
It looks like you want to subscribe to an observable which can provide the data, and once it comes in, you can then initialize your chart. Usually, we would want to have the HTTP call occur within a service, but to simplify, this is how we could do with within a component:
import {HttpClient} from '#angular/common/http';
import {Observable} from 'rxjs/Observable';
import {Component, OnInit} from '#angular/core';
export class MyChart implements OnInit {
constructor(private http: HttpClient) { }
private getData() {
let url = '[SOME-URL]' // your path to the data API endpoint
return this.http.get(url) as Observable<Array<any>>; // you would want to use correct typings here, instead of <any>
}
ngOnInit() {
this.getData().subscribe((data: any) => {
console.log(data);
// assign your data here, and then initialize your chart.
});
}
}
I just found out what I was doing wrong: I'm using axios, which is promise-based, so taking #JeffFhol's suggestion into account, my two instances were blank since I was initializing the chart at the same time I was making the API request.
The solution was to initialize the chart in the then clause of the axios request, which ensures that my instances aren't empty.
Here's the snippet that worked:
axios({
method: 'post',
url: 'url_to_api',
headers: {
'Content-Type' : 'application/json'
// custom data headers, etc.
},
data: {
// data to be sent
}
})
.then(response => {
this.weight_dates = response.data.weight_date;
this.weight_data = response.data.weight_data;
// code for chart here
})
.catch(error => {
console.log(error)
})
I'm new to AngularJS for a project and I'm trying to extract a json array from a http response to use in a list.
The response looks like this:
{
"DFH0XCMNOperationResponse": {
"ca_return_code": 0,
"ca_inquire_request": {
"ca_last_item_ref": 150,
"ca_item_count": 15,
"ca_cat_item": [
{
"ca_cost": "002.90",
"in_stock": 119,
"ca_description": "Ball Pens Black 24pk",
"on_order": 0,
"ca_department": 10,
"ca_item_ref": 10
},
{
"ca_cost": "002.90",
"in_stock": 6,
"ca_description": "Ball Pens Blue 24pk",
"on_order": 50,
"ca_department": 10,
"ca_item_ref": 20
}
],
"ca_list_start_ref": 0
},
"ca_response_message": "+15 ITEMS RETURNED",
"ca_request_id": "01INQC"
}
}
The code for the resource and request looks like this:
.factory('getCatalog', ['$resource', function($resource){
return $resource('catalogmanagertest/v1/apps/bca45894-92f7-49dc-ae54-b23b89ab6c73/catalog', {}, {query: {method:'POST'}});
}]);
And the controller code relevant looks like this:
angular
.module('catalogController', ['ngMaterial', 'ngResource'])
.controller('catalogController', ['$scope', 'getCatalog', 'catalog', function($scope, getCatalog, catalog) {
$scope.debug = getCatalog.query(); // set scope catalog to array from zOS
$scope.catalog = catalog.ca_cat_item;
$scope.message = "This is a test order message";
this.tiles = buildGridModel({
icon : "avatar:svg-",
title: "",
cost: "€",
background: "",
stock: ""
});
function buildGridModel(tileTmpl){
var it, results = [ ];
var tmp = $scope.debug.DFH0XCMNOperationResponse.ca_inquire_request.ca_cat_item;
console.log(tmp);
The next to last line is what I'm having trouble with. How do extract the expected array? I get the newbie error when I do the console.log:
TypeError: Cannot read property 'ca_inquire_request' of undefined
Replace
$scope.debug = getCatalog.query();
with
getCatalog.query().$promise.then(function (result) {
$scope.debug = result;
console.log($scope.debug.DFH0XCMNOperationResponse.ca_inquire_request.ca_cat_item);
});
Here You can see I just converted api call into the promise.In your code before console is logging variable before response come.
i am tried to delete data from my DB using the ext.js script below:
it seem to be working on the browser when i clicked on the icon "Delete" but when i clicked on some other toolbar tap some whereat the browser. it was reloaded with my same data on the row grid. I really don't know that i only delete only the Array but not delete the actual DB by sending wrong servers or methods. I don't know. I am tried using different method to delete it but it same problem came back.
Can anyone help me? I am new to ext.javascript or ext.Ajax ...etc..
codes:
var userHistoryGrid = Ext.create('Ext.grid.Panel', {
width: 880,
height: 450, //autoHeight: true, collapsible: false, title: 'Employee\'s Request History', icon: 'images/newtodo1.png', store: userHistoryStore, multiSelect: false, columnLines: false, enableColumnHide: false, enableColumnMove: false, enableColumnResize: false, selType: 'rowmodel',
viewConfig: {
emptyText: 'No prior requests',
stripeRows: false,
enableTextSelection: true,
getRowClass: function (record) {
return record.get('Status') == 'Approved' ? 'normal-row' : 'hilite-row';
}
},
items: [{
icon: 'images/delete.png',
tooltip: 'Delete Request',
handler: function (grid, rowIndex, colIndex) {
record = grid.getStore().getAt(rowIndex);
cellvalue = record.get('Delete');
if (cellvalue != 'Delete') {
Ext.MessageBox.confirm(
'Confirm Deletion',
'Delete this request?',
function (btn) {
if (btn == 'yes') {
cellvalue = record.get('EventID');
Ext.Ajax.request({
url: 'delUserHistoryGrid.asp',
async: false,
method: 'DELETE',
params: {
id: userHistoryStore
},
timeout: 30000,
success: function (result) {
userHistoryStore.reload();
userinfoStore.reload();
}
});
//delete userHistoryStore[rowIndex];
userHistoryStore.removeAt(rowIndex);
//eventStore.destroy(rowIndex);
//userHistoryStore.destroy(rowIndex);
//record.EventID.removeAt(grid);
userinfoStore.reload();
} else {
rowEditing.cancelEdit();
}
});
}
}
},
Some hints to help you pinpoint your issue:
Do not remove the record from the store after the ajax call. Only do it if it was succssful. Move userHistoryStore.removeAt(rowIndex); inside the success callback.
I don't think async: false actually exists. So your ajax call returns immediately. You should continue the flow of execution in the callback.
Add a failure callback and check (breakpoint or log) the reponse you get. You should also check the response in the success case as there might be some message of interest there too. Depends on the service.
Use your browsers dev tools and check the network. You should first verify that the ajax call is executed succesfully and then that you receive a valid reply. Check the response code. If it's not in the 200s it's an error. You can search the web more once you see the response code you get.
Without knowing anything about your services or your app I think passing the whole store as your id param is probably wrong. Shouldn't you pass the cellvalue?
Using ng-grid with server side sorting and paging. It works great, with one caveat: the initial rendering makes two calls to get data from my service.
I'm not sure how easy (or hard) this would be to replicate in a jsFiddle or plunker.
Here is my controller code:
function reportQueueController($scope, $location, reportDataService) {
function init() {
$scope.state = {};
}
$scope.setPagingData = function (data) {
$scope.reportQueueList = data.Data;
$scope.totalServerItems = data.TotalItems;
};
$scope.$watch('pagingOptions', function(newVal, oldVal) {
if (newVal === oldVal) return;
getPagedDataAsync();
}, true);
$scope.pagingOptions = {
pageSizes: [25, 50, 100, 'All'],
pageSize: 25,
currentPage: 1
};
$scope.$watch('gridOptions.ngGrid.config.sortInfo', function (newVal, oldVal) {
if (newVal === oldVal) return;
$scope.state.sortField = newVal.fields[0];
$scope.state.sortDirection = newVal.directions[0];
$scope.pagingOptions.currentPage = 1;
getPagedDataAsync();
}, true);
$scope.gridOptions = {
data: 'reportQueueList',
enablePaging: true,
enableRowSelection: false,
showFooter: true,
pagingOptions: $scope.pagingOptions,
totalServerItems: 'totalServerItems',
enableSorting: true,
useExternalSorting: true,
sortInfo: { fields: ['CustomerName'], directions: ['asc'] },
filterOptions: $scope.filterOptions,
columnDefs: [
{ field: 'CustomerName', displayName: 'Customer' },
{ field: 'ParentCustomerName', displayName: 'Parent' },
{ field: 'Name', displayName: 'Report Name' },
{ field: 'Emails', displayName: 'Email Recipients', cellTemplate: emailCellTemplate },
{ cellTemplate: editCellTemplate, width: '50px' }
]
};
function getPagedDataAsync() {
console.log('in get data'); //this get logged twice
reportDataService.getReportQueueList($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.state.emailAddress, $scope.state.reportSearch, $scope.state.sortField, $scope.state.sortDirection).then(function(data) {
$scope.setPagingData(data);
});
};
init();
}
Since Angular is going to call your watch at least twice, maybe more due to dirty processing, per $digest cycle you could use debounce. This is similar to what windows event listeners sometimes do. underscore (http://underscorejs.org) and lo-dash (http://lodash.com) both offer a _.debounce() you can use right out of the box.
_.debounce() allows you to say that a function should run, at most, once every per the specified number of milliseconds- no matter how many times the function is actually called. So you might do something like:
var checkSortData = _.debounce(function(e) {
$scope.state.sortField = newVal.fields[0];
$scope.state.sortDirection = newVal.directions[0];
$scope.pagingOptions.currentPage = 1;
getPagedDataAsync();
}, 500); // Run no more than once every 500 milliseconds
As you'd imagine underscore uses $timeout to do this, so you could write your own debounce if you preferred.
Using debounce could help with performance/server load too by minimizing server calls.
But rather than paying the performance price of polling the server to see if it has updated you might also consider using something like http://socket.io. Then you wouldn't have to poll using a watch, you can just attach an event listener on the client side. Here's an article on using socket.io with Angular written by Brian Ford: http://www.html5rocks.com/en/tutorials/frameworks/angular-websockets/
Your code looks correct, check if you are using unobtrusive js file twice, like
jquery.validate.unobtrusive.js
jquery.validate.unobtrusive.min.js
Or the same file is adding twice.
I have two AJAX requests. One of the request ($.post(/updatechart, [...])) is triggered repeatedly using setInterval(). The second one ($.post(/updateperiod, [...])) is triggered when an item from a dropdown-menu is chosen. Because of the second request, the first one stops working after a while, if I trigger the second one a few times. Sometimes, they both stop working. Can someone tell me how I can fix this?
EDIT:
stops working = request is not sent to the server anymore
EDIT2: Thanks to IcePickle I fixed the issue. I was not sending a response to the second AJAX request.
var retrieved;
var period_types = {
week: "Expenses this week",
month: "Expenses this month",
year: "Expenses this year"
};
$(document).ready(function(){
setInterval(function() {
updateGraph();
}, 1000);
$(".dropdown-item").click(function() {
var new_period = $(this).attr('value');
$.post("/updateperiod", data = {period: new_period});
});
});
function updateGraph() {
$.post("/updatechart", function(response) {
retrieved = response;
drawGraph(retrieved);
});
}
function drawGraph(response) {
var x_axis = []
var y_axis = []
var data = [];
response.db.forEach(element => {
x_axis.push(element.amount);
y_axis.push(element.category);
});
data = [
{
type: 'bar',
y: y_axis,
x: x_axis,
orientation: 'h',
marker: {
color: 'rgb(33, 40, 109)'
}
}
];
Plotly.newPlot('myDiv', data);
document.getElementById("p1").innerHTML = period_types[response.period];
}
You can add settings parameter on the $.post(), that is equal to $.ajax() method, where you can set the option:
settings: {
"async": "false"
}
So you can make multiple ajax request on the page.