I'm trying to call a factory with $http. In a browser I check the network tab and I see that the call has come trough and that the data is there but for some reason this code:
$scope.naloziPodatke = function () {
if (typeof $scope.Obdobje_do === 'undefined' || typeof $scope.Obdobje_do === 'undefined') {
alert("Napaka. Obdobje ni nastavljeno.");
} else {
getData.gData($scope.Obdobje_od.toLocaleDateString("en-US"), $scope.Obdobje_do.toLocaleDateString("en-US")).success(function (d) {
console.log(d); $scope.data = d;
for (var i = 0; i < $scope.data.d.length; i++) {
var virTasks = [];
for (var j = 0; j < $scope.data.d.SeznamVirov.length; j++) {
virTasks.push({ id: $scope.data.d[i].SeznamVirov[j].Id, subject: "", from: $scope.data.d[i].SeznamVirov[j].ObdobjeOd, to: $scope.data.d[i].SeznamVirov[j].ObdobjeDo, color: $scope.barve[colorCount], data: { id: $scope.data.d[i].SeznamVirov[j].Vir } });
}
$scope.dasData.push({
id: $scope.data.d[i].Id, name: $scope.data.d[i].Naziv, tasks: virTasks
});
if (colorCount + 1 === barve.length) {
colorCount = 0;
} else {
colorCount++;
}
}
console.log($scope.dasData);
});
}
}
Returns an error: Cannot read property 'd' of undefined.
d should be an array that .net serializer makes. It's there, browser sees it but angular does not.
You will notice that i have a console.log(d); before the for loop starts and this is the screenshot (dont get how console.log gets the data but the for loop doesnt (it's the same if i try to loop trough d or if i'm saving it's reference into $scope.data):
The service is very simple:
hermesGantt.factory('getData', ['$http', function ($http) {
return {
gData: function (obdOd, obdDo) {
return $http({ method: 'POST', url: 'index.aspx/Filtercasvir', data: { 'odObd': obdOd, 'doObd': obdDo } });
}
}
}]);
Any ideas?
You have a bug in second inner loop. Correct is:
for (var j = 0; j < $scope.data.d[i].SeznamVirov.length; j++) ...
it's not possible what you have write, data.d.something. maybe it's data[index].d[index] etc.. etc.. to let you know it, do the console.log(data) so you can see the entire response fields
EDIT
seeing your image it's clear what i have said before, d is a field that has as a value an array. To access at any value you need to put the index of the elements value in the d field. take a look at the documentation for the json array, it is really use full in angularjs.
Related
I'm triying to change a div value after an API consult and if/else statement in react. Per example, in angular with scope i can have some value and change it after an if/else statement, something like:
$scope.text = ""
if(something){
$scope.text = "Hello"
}
else {
$scope.text = "Goodbye"
}
I need to do the same in react. Here's part of my code so far:
function QuantityBtn() {
const theIds = [{'id': 1, 'value': "one"}, {'id': 2, 'value': 'two'}]
let special = null
const findData = {
method: 'GET',
url: "/api/",
headers: {
'Content-Type': 'application/json',
},
};
axios(findData)
.then(function(data) {
const returnedInfo = data.data;
for(var i = 0; i < theIds.length; i++){
for(var j = 0; j = returnedInfo.length; j++){
if(theIds[i].id == returnedInfo[j].id){
return special = true
}
else{
return special = false
}
}
}
})
.catch(err => console.error(err))
return (
<div
className="miTest"
>{special}</div>
)
}
So, as you can see what i'm triying to do is:
Consult the API
With the data response (const returnedInfo) i run over the array (const theIds) and the response itself and make a validation: if exist an id of the array inside of the response, the value on the returned div have to change to true, and if not (else statement), the value have to change to false;
My problem it's simple: the variable value is not changing. Can you tell me, please, if there's something else to do to change it? I've checked response of the api and run some tests, and there's one of the ids of the array that is equal to the id in the response. So the validation it's fine. I just need to find out how to change the variable let special
As i'd said before, i'm using react and i'm barely new.
EDIT
I've just discovered on the console that the value is changing, the problem it's on the front, the return with the div is not catching and printing the value... Do you know why?
Thanks in advance
remove the return before the true and false
if(theIds[i].id == returnedInfo[j].id){
special = true
}
else{
special = false
}
I'm trying to get a list of quantities (identified as cantidad) chosen of each product (as id) to my flask controller. Since wtform didn't adapted well to my needs I had to use json and jQuery, but no matter what I do, the list of objects is seen as empty in the controller, even if in the frontend it does has something inside.
This is the JavaScript:
This function posts the order which should be a list of quantities with id assigned:
<script type="text/JavaScript">
function setPedido(order){
console.log(order);
$.ajax({
url: "{{url_for('main.pedido')}}",
type: 'POST',
data: JSON.stringify(order),
contentType: 'application/json;charset=UTF-8',
success: function(response) {
if (response.redirect) {
window.location.href = response.redirect;
}
}
});
};
When "pedido" (order) button is clicked, gets all assigned quantities and their respective product IDs:
$(".btnPedido").click(function(){
var order = []
$(function() {
var lines = $(".btnAgregar.active")
for(var i = 0; i < lines.length; i++) {
console.log(lines[i]);
order.push({
'id': $(lines[i]).closest("tr").find('.btnPedido').val(),
'cantidad' : $(lines[i]).closest("tr").find('.inpCantidad').val()
});
}
});
setPedido(order);
});
This marks each quantity input as ready to order:
$(".btnAgregar").click(function(){
if($(this).val() == 0){
$(this).val(1);
$(this).text("Agregado");
}else{
$(this).val(0);
$(this).text("Agregar");
}
$(this).toggleClass('btn-info btn-success active');
});
</script>
This shows in the console:
And this in flask controller (notice data):
The problem was at this function, paying better attention i declared a function inside another function, wich is executed at a different scope than setPedido(order), at wich point it stills empty.
To make it worse, the console.log inside the inner function where misleading.
$(".btnPedido").click(function(){
var order = []
$(function() {
var lines = $(".btnAgregar.active")
for(var i = 0; i < lines.length; i++) {
console.log(lines[i]);
order.push({
'id': $(lines[i]).closest("tr").find('.btnPedido').val(),
'cantidad' : $(lines[i]).closest("tr").find('.inpCantidad').val()
});
}
});
setPedido(order);
});
The correct way to do it is:
$(".btnPedido").click(function(){
var order = []
var lines = $(".btnAgregar.active")
for(var i = 0; i < lines.length; i++) {
console.log(lines[i]);
order.push({
'id': $(lines[i]).closest("tr").find('.btnPedido').val(),
'cantidad' : $(lines[i]).closest("tr").find('.inpCantidad').val()
});
}
setPedido(order);
});
I am trying to delete values selected by the user in a loop.
for (var i = 0; i < myArray.length; i++) {
MyService.myMapService.delete({id: myArray[i].myId }, myArray[i], function (response) {
if (response.isSuccessful) {
MyService.removeMyValue(myArray[i].myId);
}
})
}
However, I keep receiving the following error
angular.js:13920 TypeError: Cannot read property 'myId' of
undefined
Please help!
What happening is, your for loop is getting executed for all MyService.myMapService.delete function call and your i is becoming myArray.length. There after when myMapService.delete async call completed, it tries to do myArray[i].myId(where i is array length, then myArray[i] would be undefined). In this case you have to preserve value of by wrapping it to self executing function.
Code
for (var i = 0; i < myArray.length; i++) {
(function(j) {
MyService.myMapService.delete({
id: myArray[j].myId
}, myArray[j], function(response) {
if (response.isSuccessful) {
MyService.removeMyValue(myArray[j].myId);
}
})
})(i);
}
I have 2 API calls.
The second API call depends on the Property ID returned to make the second API call to check if each of these properties has parking.
If it does, then I add details of that property to an object and push the object into an Array.
The second API call is nested inside the first. After I've looped through all the properties, I check if the Array length is more than 0, if it is then I can display the returned properties in page, else it shows an error.
The problem is even when there are properties returned with parking, the else statement or error function executes, as well as displaying properties on the page.
Is there a way to complete the nested Promise before checking if my Array is more than 0?
Here's my code:
$scope.viewPropertyList = function(latlong) {
$scope.locationError = false;
var latlongArray = latlog.split('::');
var searchLat_scope = latlongArray[0];
var searchLon_scope = latlongArray[1];
if (searchLat_scope && searchLon_scope) {
var data = Property.getAllProperties({
dest: 'property',
apikey: API_KEY,
lat: encodeURIComponent(searchLat_scope),
limit: 10,
lon: encodeURIComponent(searchLon_scope)
}).$promise.then(function(success) {
var propertyMarkers = [];
$scope.dbMarkers = 0;
for (var i = 0, l = success.property.length; i < l; i++) {
(function(i) {
Property.getProperty({
dest: 'property',
propertyId: success.property[i].name,
apikey: API_KEY
}).$promise.then(function(propertyData) {
for (var j = 0, k = propertyData.services.length; j < k; j++) {
if (propertyData.services[j].name === "parking") {
var obj = {
"propertyName": success.property[i].propertyName,
"telephone": success.property[i].telephone,
"postcode": success.property[i].address.postcode,
"city": success.property[i].address.city,
"county": success.property[i].address.county,
"addressLine1": success.property[i].address.addressLine1
};
propertyMarkers.push(obj);
}
}
if (propertyMarkers.length != 0) {
$scope.dbMarkers = propertyMarkers;
$scope.selectedLat = searchLat_scope;
$scope.selectedlog = searchLon_scope;
} else {
$scope.locationErr = true;
$scope.errorMsg = "No properties found";
}
});
})(i);
}
}, function(error) {
$scope.locationErr = true;
$scope.errorMsg = "Something went wrong, please try again";
});
}
}
Two main things :
there's no attempt to aggregate multiple promises generated in a loop.
the if (propertyMarkers.length > 0) {...} else {...} is too deeply nested.
Minor :
the inner iteration can break as soon as 'parking' is found. If it continued and further 'parking' was found, then duplicate markers would be created.
$scope.viewPropertyList = function(latlong) {
$scope.locationError = false;
var latlongArray = latlog.split('::');
var searchLat_scope = latlongArray[0];
var searchLon_scope = latlongArray[1];
if (searchLat_scope && searchLon_scope) {
Property.getAllProperties({
dest: 'property',
apikey: API_KEY,
limit: 10,
lat: encodeURIComponent(searchLat_scope),
lon: encodeURIComponent(searchLon_scope)
}).$promise.then(function(success) {
var propertyMarkers = [];
$scope.dbMarkers = 0;
// create an array of promises by mapping the array `success.property`.
var promises = success.property.map(function(prop) {
return Property.getProperty({
dest: 'property',
propertyId: prop.name,
apikey: API_KEY
}).$promise.then(function(propertyData) {
for (var j=0, k=propertyData.services.length; j<k; j++) {
if (propertyData.services[j].name === 'parking') {
propertyMarkers.push({
'propertyName': prop.propertyName,
'telephone': prop.telephone,
'postcode': prop.address.postcode,
'city': prop.address.city,
'county': prop.address.county,
'addressLine1': prop.address.addressLine1
});
break; // 'parking' is found - no point iterating further
}
}
});
});
/* ******** */
// Aggregate `promises`
$q.all(promises).then(function() {
// This block is now un-nested from its original position,
// and will execute when all `promises` have resolved.
if (propertyMarkers.length > 0) {
$scope.dbMarkers = propertyMarkers;
$scope.selectedLat = searchLat_scope;
$scope.selectedlog = searchLon_scope;
} else {
$scope.locationErr = true;
$scope.errorMsg = 'No parking found';
}
});
/* ******** */
}).catch(function(error) {
$scope.locationErr = true;
$scope.errorMsg = 'Something went wrong, please try again';
});
} else {
$scope.locationErr = true;
$scope.errorMsg = 'Problem with lat/lng data';
}
}
Notes :
that the outer iteration is now coded as success.property.map(), which returns promises and avoids the need for an IIFE.
Extra error handling added
If I got your problem right, you want all Property.getProperty promises of success.property are resolved before going to the success function to check propertyMarkers length.
In that case, you need $q.all to resolve all the Property.getProperty promises for you.
In your for (var i = 0, l = success.property.length; i < l; i++) { appends all the promises into an array
Property.getProperty({
dest: 'property',
propertyId: success.property[i].name,
apikey: API_KEY
})
then use $q.all(arrPromises).then(function(propertyData) { to do the following check.
One more thing worth to mention, promise chaining can be easily achieved by $promise.then(successFn, failFn).then(successFn, failFn).then.... Every time you call then() will create another promise which allows you to chain to next promise and pass value to the next.
I'm looking for a AngularJS-based way to prevent multiple submits per task.
I don't need buttons to be disabled after submission or close the form and wait for the task to be completed. Instead, I need requests to be unique.
To be more detailed, I need $http.get and $http.post stop sending multiple same requests.
Any Ideas?
According to this article, you can use provider decorator.
NOTE: this approach is based on angular-api
https://gist.github.com/adambuczynski/354364e2a58786e2be71
UPDATE
I've changed a little part in your suggested solution, because returned promises have lost .success and .error and .then.
Just use this edited code to have all of those functions working:
.config(["$provide", function ($provide) {
$provide.decorator('$http', function ($delegate, $q) {
var pendingRequests = {};
var $http = $delegate;
function hash(str) {
var h = 0;
var strlen = str.length;
if (strlen === 0) {
return h;
}
for (var i = 0, n; i < strlen; ++i) {
n = str.charCodeAt(i);
h = ((h << 5) - h) + n;
h = h & h;
}
return h >>> 0;
}
function getRequestIdentifier(config) {
var str = config.method + config.url;
if (config.data && typeof config.data === 'object') {
str += angular.toJson(config.data);
}
return hash(str);
}
var $duplicateRequestsFilter = function (config) {
if (config.ignoreDuplicateRequest) {
return $http(config);
}
var identifier = getRequestIdentifier(config);
if (pendingRequests[identifier]) {
if (config.rejectDuplicateRequest) {
return $q.reject({
data: '',
headers: {},
status: config.rejectDuplicateStatusCode || 400,
config: config
});
}
return pendingRequests[identifier];
}
pendingRequests[identifier] = $http(config);
$http(config).finally(function () {
delete pendingRequests[identifier];
});
return pendingRequests[identifier];
};
Object.keys($http).filter(function (key) {
return (typeof $http[key] === 'function');
}).forEach(function (key) {
$duplicateRequestsFilter[key] = $http[key];
});
return $duplicateRequestsFilter;
})
}])
It could be a performance issue but following idea could solve your problem.
Store the each request URL and DATA as key value pair on a variable. URL should be KEY. For Same URL multiple submission can be stored in a Array.
Then for any new call check the URL if it present in your stored object, then compare the data with each object thorughly (deep check, it is costly though).
If any exact match found then stop the processing. As same request came.
Other wise proceed and don't forget to store this data also.
But it is costly since need to check the data which could be havy.
Note: At the time of storing the data you could convert it to JSON String so it will be easier to compare between String.
here is the Code Algo
YourService.call(url, params) {
var Str1 = JSON.stringify(params);
if(StoredObj[url]) {
for each (StoredObj[url] as Str){
if(Str === Str1) {
return;
}
}
}
else {
StoredObj[url] = []; //new Array
}
StoredObj[url].push(Str1);
Call $http then;
}