How to resolve function and call other function in angular - javascript

I have two functions and I want to call one function after other only first function is resolved successfully.
$scope.createNewWorkModule = function (data, selectedUser) {
$scope.workOrderInfo = $localStorage.workOrderInfo;
$scope.createNewWorkOrder($scope.workOrderInfo).then(function (response) {
$scope.workOrderId = $localStorage.workOrderId;
var newWM = {
name: data.name,
};
$scope.myPromise = operationsFactory.createWorkModule(angular.toJson(newWM)).success(function (response) {
$rootScope.workModules = response.result;
return $scope.workOrder;
})
});
};
$scope.createNewWorkOrder = function (data) {
var newWD = {
name: data.name,
description: data.description,
user_id: $cookies.userId
};
$scope.myPromise = operationsFactory.createWorkOrder(angular.toJson(newWD)).success(function (response) {
$localStorage.workOrderId = response.result.id;
})
return $localStorage.workOrderId;
};
I am trying to call $scope.createNewWorkOrder with .then but it is giving error that
TypeError: Cannot read property 'then' of undefined
at Scope.$scope.createNewWorkModule (work-order-create-controller.js:36)
at $parseFunctionCall (angular.js:12158).
How do I fix this?
Update:
Unable to update the view with data retrieved:
<div class="panel panel-default">
<div class="panel-heading font-bold">
<span>List of Work Modules</span>
</div>
<ul ng-repeat="wm in workModules" style="list-style: none">
<li>{{wm.name}}</li>
<li>{{wm.description}}</li>
</ul>
</div>

Your asynchronous functions should always return the promises.
Make sure the then success functions always return the values needed by the next handler in the chain (and don't use the deprecated .success method as that doesn't chain correctly, always use .then but be aware of the slightly different parameter is gets from $http results).
Also try not to put things into $scope unless you really need them there, probably many of your functions can be just functions and the values could be local variables in the controller.
Note that once you are using .then you can issue a new call at the end of one success handler and process the result with another .then at the same level, no need to nest things further.
$scope.createNewWorkModule = createNewWorkModule; // Do you need both this
$scope.createNewWorkOrder = createNewWorkOrder; // and this?
function createNewWorkModule(data, selectedUser) {
$scope.workOrderInfo = $localStorage.workOrderInfo;
return createNewWorkOrder($scope.workOrderInfo)
.then(function (workOrderId) {
$scope.workOrderId = workOrderId;
var newWM = {
name: data.name,
};
return operationsFactory.createWorkModule(angular.toJson(newWM));
})
.then(function (response) {
// here we have response from the createWorkModule call
$rootScope.workModules = response.data.result;
return $scope.workOrder;
});
};
function createNewWorkOrder(data) {
var newWD = {
name: data.name,
description: data.description,
user_id: $cookies.userId
};
return operationsFactory.createWorkOrder(angular.toJson(newWD))
.then(function (response) {
var workOrderId = $localStorage.workOrderId = response.data.result.id;
return workOrderId;
})
};

You are getting error then is not a function, because the value returned is undefined as $localStorage.workOrderId is resolved async. Ideally you should return a promise.
return operationsFactory.createWorkOrder(angular.toJson(newWD)).success(function (response) {
$localStorage.workOrderId = response.result.id;
return $localStorage.workOrderId;
});

Related

angular 1 promise call http works, but not with fake data from json structure , promise.then not a function

I have angularjs controller that return $http data fine, but I need to just return some hardcoded json structure data , but I'm getting promise.then is not a function.
Seems it is not returning , like I need another return?
Controller:
var promise = hearingFactory.getHearingSummary();
promise.then(function (response) {
vm.myData = response;
console.log('getHearingSummary promise data', vm.myData);
}, function (err) {
console.log('err', err);
});
Service
var hearingFactory = function ($http) {
var factory = {};
factory.getHearingSummary = function () {
var url = "";
url = baseUrl + "lib/questions";
url = "test.json"
//WORKS
return $http.get(url).then(function (result) {
console.log('service',result.data);
return result.data;
});
// DOESN"T work ( I comment out the above code)
return {
"flightData": [
{
"MultiCarrier": false,
"Id": "O1"
}
]
}
}
return factory;
};
nothing is wrong with my controller code, nor the overall service code
seems to be that double return promise in the .then for $http "works"
perhaps i need a true "promise" for the json structure of data, if so , how would i write that?
The first one "works" because .then() produces a promise. Your second return statement is returning a plain object, which isn't a promise. You're trying to call .then on something that isn't a promise.
So return a promise:
return $q.when({
"flightData": [
{
"MultiCarrier": false,
"Id": "O1"
}
]
});

JQuery Return the Object with the Promise

I've got multiple pages of widgets. The contents of the widgets are static, though their display can change. I need to be able to store these, so I'm building an multi-dimensional object.
I need to store the object and display the object.
Here's a simplified version of my factory:
const createWidget = ({
id = undefined,
name = 'new widget',
style = 'vertical_list',
html = undefined,
} = {}) => ({
id,
name,
style,
data,
constructWidget () {
return $.ajax({
url: '/my/url',
type: 'POST',
data: {
'_token' : window.xsrf_token,
'widget_id': this.id,
},
dataType: 'json',
}).then(reponse => {
let widget = response.widget;
this.name = widget.name;
this.style = widget.style;
this.html = widget.html;
});
},
})
That hydrates the object with everything just fine, but I can't get the object back.
let book = {};
let page = 'example page';
book[page] = book[page] || {};
let widget_id = 88;
// TRYING TO STORE
// this just give me the promise and I can't get at the object :(
book[page][widget_id] = CreateWidget({id: widget_id}).constructWidget();
// TRYING TO DISPLAY
let widget = book[page][widget_id];
$(`#current_page`).append(`
<div id="widget_${widget.id}" class="${style}">
<b>${widget.name}</b>
${widget.html}
</div>`
);
So? Why is this approach stupid and how do I fix it? I've tried messing with promises a bunch, but without access to the hydrated object I can't seem to do a dang thing.
you need to wait for these promises somehow
simplest (well, the shorter code example at least) way is to use async/await
async function() {
book[page][widget_id] = await CreateWidget_1({id: widget_id}) //the promise :(
book[page][widget_id] = await CreateWidget_2({id: widget_id}) //maybe...
$(`#current_page`).append(`<div>${book[page][widget_id]}</div>`); //nope, that'll be undefined because the promise isn't complete this isn't an asynch approach, dummy
or the longer promises based
Promise.all[CreateWidget_1(...), CreateWidget_2(...)])
.then(function() { $(`#current_page`).append(...) })
Also, chaining is one of the most important concepts of promises, to properly use promise, they need to be returned, both your functions need to return the promise (only one returns it)
The issue was that I needed to return this as part of the promise. I wasn't doing that. Huge thanks to #JaromandaX for that.
Returning the promise and the object means that I continue on a asynchronous path. Simplified example answer below.
const createWidget = ({
id = undefined,
name = 'new widget',
style = 'vertical_list',
html = undefined,
} = {}) => ({
id,
name,
style,
data,
constructWidget () {
return $.ajax({
url : '/my/url',
type: 'POST',
data: {
'_token' : window.xsrf_token,
'widget_id': this.id,
},
dataType: 'json',
}).then(reponse => {
let widget = response.widget;
this.name = widget.name;
this.style = widget.style;
this.html = widget.html;
return this; // <-- here's what I was missing.
});
},
})
let book = {};
let page = 'example page';
book[page] = book[page] || {};
let widget_id = 88;
CreateWidget({id: widget_id})
.constructWidget()
.then(widget => {
book[page][widget_id] = widget;
$(`#current_page`).append(`
<div id="widget_${widget.id}" class="${style}">
<b>${widget.name}</b>
${widget.html}
</div>`
);
})
.fail(error => console.error);
A pox upon the article that said a return inside the then was meaningless!

How to return data from promise inside JSON object? angularjs

This is my first time when I try to return data from promise inside JSON object and I stuck with this task
So common way is something like this
service js
app.factory("dataService", ["$http",
function ($http) {
function getData(id) {
return $http.get('endpoint', id)
.then(function (response) {
return response.data
});
}
return {
getData: getData
}
}])
controller js
$scope.data = {}
dataService.getData($routeParams.id)
.then (function (res) {
$scope.data = res
});
this works fine and everybody is happy
now I'm trying to assign data inside object
controller js
angular.forEach($scope.properties, function (item) {
$scope.data.properties.push({
order: item.number,
name: item.name,
value: item.value,
items: $scope.getProp(item.id)
})
});
$scope.getProp = function (id) {
return dataService.single(id)
.then (function (res) {return res});
};
service js
function single(id) {
return $http.get('endpoint' + "/" + id)
.then(function (response) {
return response.data
})
}
and now I'm getting JSON object with promise and $$state inside
I understand the nature of this problem but solution for this problem is out of range of my knowledges, so could somebody help me deal with it ?
One way to make it work is:
$scope.data.properties = [];
var promiseList = $scope.properties.map(function(item) {
var promise = $scope.getProp(item.id);
return promise.then(function (data) {
var newItem = {
id: item.id,
order: item.number,
name: item.name,
value: item.value,
items: data
};
$scope.data.properties.push(newItem);
return newItem;
});
});
$q.all(promiseList).then(function(itemList) {
console.log(itemList);
//More code here
});
The above example creates a list of promises that return objects that have the items property populated with data from the promise returned from $scope.getProps.
In addition it pushes each populated item to scope. Because the asynchronous XHRs may not complete in the order that they were started, the scope list may not be in the same order as the original.
The $q.all method however will wait for all the XHRs to complete and return the list in the original order.

How can I pass an data from factory to my controller in angularjs?

I'm trying to move all the business logic from my controller to the factory, but I'm having some trouble passing fields data.
factory.js
app.factory("Quote", function ($resource) {
// TODO: this shouldn't start with /en/
var quoteStatus = [];
var quoteLanguage = [];
var Quote = $resource("/en/quote/api/quote/:id", {}, {
retrieve: {
method: 'GET',
params: {},
isArray: true
},
query: {
method: 'GET',
params: {},
isArray: true,
url: '/en/quote/api/quote/'
},
fields: {
method: 'GET',
url: '/en/quote/api/quote/fields/ '
},
update: {
method: 'PATCH',
},
});
Quote.fields().$promise.then(function (fields) {
var tempObj = [];
for (key in fields.status) {
// must create a temp object to set the key using a variable
tempObj[key] = fields.status[key];
quoteStatus.push({
value: key,
text: tempObj[key]
});
}
for (key in fields.language) {
// must create a temp object to set the key using a variable
tempObj[key] = fields.language[key];
quoteLanguage.push({
value: key,
text: tempObj[key]
});
}
//$scope.addLanguage($scope.language);
Quote.status = quoteStatus;
Quote.language = quoteLanguage;
});
return Quote;
});
controller.js
$scope.quoteStatus = Quote.status;
However this is not working since $scope.quoteStatus is undefined. What am I missing?
Thanks in advance.
You can't expect async operation to behave in synchronous way.
Basically when controller inject Quote in its factory function that time Quote service object gets created & then calls Quote.fields(). hen you ask Quote.status inside a controller will always return undefined. You are not maintaining promise anywhere so that controller will come to know that the data is ready or not.
I think you should introduce $q.when flag there to check the Quote.fields() operation completed or not & then do get the desired variable there.
For implementing above mention thing you need to store the promise of Quote.fields() call somewhere in service. like below
var quoteFieldsPromise = Quote.fields().$promise.then(function (fields) {
/// the code will be same here
};
Then add new method which will hold of quoteFieldsPromise promise object and return the value of quoteStatus & quoteLanguage.
var getQuoteDetails = function(){
$q.when(quoteFieldsPromise).then(function(){
return { quoteStatus: Quote.quoteStatus, quoteLanguage: Quote.quoteLanguage };
})
}
But the way you have returned whole Quote object, which only has $resource object which needs to be changed. I mean to say that the getQuoteDetails method which I've created can not be return with Quote object. So I'd rather rather refactor service to below.
Service
app.factory("Quote", function($resource, $q) {
// TODO: this shouldn't start with /en/
var quoteStatus = [], //kept private if needed
quoteFieldsPromise,
quoteLanguage = [];//kept private if needed
var QuoteApi = $resource("/en/quote/api/quote/:id", {}, {
//inner code is as is
});
//preserve promise of .fields() call
quoteFieldsPromise = Quote.fields().$promise.then(function(fields) {
//inner code is as is
//below lines are only changed.
Quote.status = quoteStatus;
Quote.language = quoteLanguage;
});
var getQuoteDetails = function() {
return $q.when(quoteFieldsPromise).then(function() {
return {
quoteStatus: quoteStatus,
quoteLanguage: quoteLanguage
};
})
};
return {
QuoteApi: QuoteApi,
getQuoteDetails: getQuoteDetails
};
});
Controller
Quote.getQuoteDetails().then(function(quoteDetails){
$scope.quoteStatus = quoteDetails.quoteStatus;
$scope.quoteStatus = quoteDetails.quoteLanguage;
});

jQuery asynchronous issue undefined value

I am having difficulties with Javascript's asynchronous functions.
Code displayed below is so far almost entire code I have and I can't get it to work.
I ma trying to use Eventful API to pull some data from the server, and display it in my frontend which is created by jQuery.
So, the problem is following: function search, which is calling function Eventful.prototype.searchanje always ends up with undefined value, while a few seconds later, function searchanje console logs actual/recieved data.
I am fairly new to jQuery, and I was wondering if there is any kind of "template" for handling these things, concretely for waiting until the function returns value and then proceeding with next operations.
So far I have tried using deferred and promises, and read quite a lot tutorials and stackoverflow answers on similar subjects, but I can't get it to work properly.
Or, if deferred and promises are the right way to go, could you show me the way it is supposed to be done?
Thanks in advance
'use strict';
function Eventful(_name) {
var name = _name;
var appKey = 'appKey';
var that = this;
return {
getName: function() {
return name;
},
getAppKey: function() {
return appKey;
},
search: function() {
that.searchanje(appKey).then(function(oData) {
console.log('oData');
});
}
};
}
Eventful.prototype.searchanje = function(appKey) {
var oArgs = {
app_key: appKey,
q: 'sport',
where: 'Zagreb',
date: '2013061000-2015062000',
page_size: 5,
sort_order: 'popularity',
};
EVDB.API.call('/events/search', oArgs, function(oData) {
console.log(oData);
return oData();
});
};
On the line
EVDB.API.call('/events/search', oArgs, function(oData) {
you are passing a CALLBACK function. This function (the one that starts function(oData)) is not executed immediately. It is executed asynchronously, when the result of your API call is returned.
Try putting console.log() statements around your code, and watch the order they appear in the console. For example:
function Eventful(_name) {
var name = _name;
var appKey = 'appKey';
var that = this;
return {
getName: function() {
return name;
},
getAppKey: function() {
return appKey;
},
search: function() {
console.log('Search function called');
that.searchanje(appKey).then(function(oData) {
console.log('searchanje returned with data:');
console.log('oData');
});
}
};
}
Eventful.prototype.searchanje = function(appKey) {
console.log('function searchanje being called with appKey: ', appKey);
var oArgs = {
app_key: appKey,
q: 'sport',
where: 'Zagreb',
date: '2013061000-2015062000',
page_size: 5,
sort_order: 'popularity',
};
console.log('Calling EVDB.API.call');
EVDB.API.call('/events/search', oArgs, function(oData) {
console.log('EVDB.API callback executing with data:');
console.log(oData);
return oData();
});
console.log('finished calling EVDB.API.call');
};
I wonder if a better way ahead might be to "promisify" EVDB.API.call().
(function(app_key) {
var appKeyObj = { 'app_key': app_key },
EVDB.API.callAsync = function(path, params) {
return $.Deferred(function(dfrd) {
EVDB.API.call(path, $.extend(appKeyObj, params), function(oData) {
if (oData.error === "1") {
//translate oData.status and oData.description into a javascript Error object
// with standard .name and .message properties.
err = new Error(oData.description);
err.name = oData.status;
dfrd.reject(err);
} else {
dfrd.resolve(oData);
}
});
});
});
})('myAppKey'); //hard-coded app key
Notes:
The global namespace is avoided by :
using a self-executing anonymous wrapper
extending the EVDB.API namespace.
The "Async" suffix for a promisified method has a precendent in bluebird
From the little I understand of EVDB.API, EVDB.API.call() does just about everything, hence the single method EVDB.API.callAsync(). If necessary, further async methods could be added to EVDB.API
You might choose to use a dedicated promise lib such as bluebird or when.js in place of jQuery, In addition to including the lib, mods to the above code would be minor.
Now, instead of calling EVDB.API.call(path, params, callback) you would call EVDB.API.callAsync(path, params) to be returned a Promise.
var params = {
//app_key will be inserted automatically
q: 'sport',
where: 'Zagreb',
date: '2013061000-2015062000',
page_size: 5,
sort_order: 'popularity'
};
EVDB.API.callAsync('/events/search', params).then(function(oData) {
console.log(oData);
}, function(err) {
console.error(err);
});

Categories

Resources