I am need to refactor some code and convert it into a factory/service calls. This was the original code being cslled for an autocomplete dropdown.
$scope.querySearchManagerName = function (skill) {
console.log(skill);
//var entry = skill.replace(/ /g, "_").toLowerCase()
var query = {
"managerName" : skill
}
if(skill.length < 2){
return [query]
}
else{
return $http.post('/tdp/managerTypeahead/', query)
.then(function(result) {
return result.data;
})
.catch(function(reason) {
$scope.genericError();
}
)
}
}
The factory code I have converted to is :
var querySearchManagerName = function(skill) {
var query = {
"managerName" : skill
}
return $http.post('/tdp/managerTypeahead/', query)
.then(function(result) {
return result.data;
})
.catch(function(reason) {
$scope.genericError();
}
)
}
And calling of the factory is :
$scope.querySearchManagerName = function (skill) {
console.log(skill);
//var entry = skill.replace(/ /g, "_").toLowerCase()
var query = {
"managerName" : skill
}
if(skill.length < 2){
return [query]
}
else{
return $scope.demandFactory.querySearchManagerName(skill);
}
}
However I am getting an error :
TypeError: $scope.demandFactory.querySearchManagerName is not a function.
Any clue why i am getting it?
Related
I was having trouble while converting a synchronous function to asynchronous.
the existing code is like below
$scope.getTask = function (input, id) {
var result = '';
if (condition) {
// Get all tasks.
var tasks = $scope.getAllTasks(id);
if (!angular.isUndefined(tasks)) {
var result = 'Failed';
for (var i = 0; i < tasks.length; i++) {
if (condition) {
result = 'Success';
break;
}
}
}
}
else if (condition) {
result = 'Failed';
}
else {
if (input != null || input != '') {
result = input.toLowerCase();
}
}
return result;
}
$scope.getAllTasks = function (id) {
var xhr = new XMLHttpRequest();
var url = "/api/workflow/" + id;
xhr.open("GET", url, false);
xhr.send();
return JSON.parse(xhr.responseText);
}
But now i need to make this async , so i have tried using promises but that didnt help.
It is not resolving properly. Please find what i have tried
$scope.getStatus = function (input, id) {
return new Promise((resolve, reject) => {
var result = '';
if(condition){
getAllTasks(id).then(function(response){
var tasks = response.data;
if (!angular.isUndefined(tasks)) {
var status = 'Failed';
for (var i = 0; i < tasks.length; i++) {
if (condition) {
result = 'Success';
break;
}
}
}
resolve(result);
return result;
});
resolve(result);
}
else if (condition) {
result = 'Failed';
}
else {
if (input != null || input != '') {
result = input.toLowerCase();
}
}
resolve(result);
return result;
});
}
var getAllTasks = function (id) {
const url = "/api/workflow/" + id;
return $http({method: 'GET', url})
.then((response) => {
return resolve(response)
});
}
But this is always returning [object promise].
I need to return the value as string like ' Failed' 'Success'.
Suggest what i am missing here.
I know promise will return a promise object from docs, but how to handle this.
$scope.getStatus is used in directives to fill the columns in jquesry datatable.
Code snippet is below
'sTitle': "<strong>" + $translate("list.StatusColumn") + "</strong>",
'mData': function (data, type, val) {
return $scope.getStatus(data.input, data.id);
},
'width': "16%",
'defaultContent': ""
Do this:
first,Dont handle your http request here if you are handling it in your other promise:
var getAllTasks = function (id) {
const url = "/api/workflow/" + id;
return $http({method: 'GET', url});
}
second: stop returning anything from this promise's callback function as you are returning result that you are also setting in resolve and you can get it in success handler of then function like this:
$scope.getStatus = function (input, id) {
var result = '';
if(condition){
getAllTasks(id).then(function(response){
var tasks = response.data;
if (!angular.isUndefined(tasks)) {
result = 'Failed';
for (var i = 0; i < tasks.length; i++) {
if (condition) {
result = 'Success';
break;
}
}
}
return result;
});
return result;
}
else if (condition) {
result = 'Failed';
}
else {
if (input != null || input != '') {
result = input.toLowerCase();
}
}
return result;
}
console.log($scope.getStatus());
I am creating a react native application.
I have a back button that fires the function findItem. findItem the uses async method searchJson. searchJson searches recursive json to find parent object based on id. However it never returns any results.
findItem:
findItem() {
//Pass null so top level json will be pulled
let result = this.searchJson(null).done();
let abv = 2;
// this.setState(previousState => {
// return {
// data: result,
// parentID: result.parentid
// };
// });
}
searchJson:
async searchJson(object) {
return new Promise(resolve => {
//use object or pull from porp - all data
let theObject = object == null ? this.props.data : object;
var result = null;
if (theObject instanceof Array) {
for (var i = 0; i < theObject.length; i++) {
result = this.searchJson(theObject[i]);
if (result) {
break;
}
}
}
else {
for (var prop in theObject) {
console.log(prop + ': ' + theObject[prop]);
if (prop == 'id') {
if (theObject[prop] == this.state.parentID) {
return theObject;
}
}
if (theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
result = this.searchJson(theObject[prop]);
if (result) {
break;
}
}
}
}
if(result != null)
resolve(result);
});
}
Any help will be greatly appreciated.
Ok so I never got this to work but my workaround was this.
I Modified the findItem method:
findItem() {
let FinNode = null;
for (var node in this.props.data) {
FinNode = this.searchJson(this.state.parentID, this.props.data, this.props.data[node].book);
if (FinNode != null) {
this.setState(previousState => {
return {
data: FinNode[0].book.parentid == "" ? null : FinNode,
parentID: FinNode[0].book.parentid
};
});
break;
}
}
}
And then the searchJson:
searchJson(id, parentArray, currentNode) {
if (id == currentNode.id) {
return parentArray;
} else {
var result;
for (var index in currentNode.books) {
var node = currentNode.books[index].book;
if (node.id == id)
return currentNode.books;
this.searchJson(id, currentNode.books, node);
}
return null;
}
}
This allowed for all my nodes to be searched and the for loop made so that there is no need for async. This does have some drawbacks but seems to work decently without any massive performance issues.
I'm using angular.js with C# web service and I need to increment ng-repeat item by item to show to the user as the data is updated, to do this I'm trying to use $http.get within loop for refresh data in each item. But its not working
for (var i = 0; i < conditions.length; i++) {
var configFullAsset = {
params: {
Field: Field,
SAM_ConnectionString: SAM_ConnectionString,
TreeElemId: conditions[i][0],
ConditionDate: conditions[i][1]
}
};
$http.get('application.asmx/getExtFullAssetHealth', configFullAsset)
.success(function (responseExt) {
console.log("Element: ", i);
if (i == 0)
{
$scope.showData = responseExt;
$scope.fullAssetTable_loading = false;
$scope.fullAssetTable_loaded = true;
}
else
$scope.showData = $scope.showData.concat(responseExt);
//console.log("Data item: ", $scope.showData[i].Tag);
$scope.fullData = $scope.showData;
$scope.filterData(customFilter);
})
.catch(function (err) {
console.log("Error get object: ", err);
})
.finally(function () {
// Hide loading spinner whether our call succeeded or failed.
//$scope.loading = false;
$scope.fullData = $scope.showData;
$scope.filterData(customFilter);
$scope.fullAssetTable_loading = false;
$scope.fullAssetTable_loaded = true;
console.log($scope.fullData);
});
}
The main problem into your code is the fallowing: you use i as index in the success method but is not what you expected because the loop is over until your first success will be called.
You can build the requests like this in the first phase, is much easier to read:
function buildRequests() {
return conditions.map(function(condition) {
var configFullAsset = {
params: {
Field: Field,
SAM_ConnectionString: SAM_ConnectionString,
TreeElemId: condition[0],
ConditionDate: condition[1]
}
};
return $http.get('application.asmx/getExtFullAssetHealth', configFullAsset);
});
}
Than you can handle all the requests like this:
function handleRequests() {
var requests = buildRequests();
$q.all(requests)
.then(handleRequests)
.catch(function(error) {
console.log(error);
})
.finally(function() {
$scope.fullData = $scope.showData;
$scope.filterData(customFilter);
$scope.fullAssetTable_loading = false;
$scope.fullAssetTable_loaded = true;
});
}
Than to iterate over each result to make the changes:
function handleResults(results) {
results.forEach(function(response, i) {
console.log("Element: ", i);
if (i == 0)
{
$scope.showData = response;
$scope.fullAssetTable_loading = false;
$scope.fullAssetTable_loaded = true;
}
else
$scope.showData = $scope.showData.concat(response);
//console.log("Data item: ", $scope.showData[i].Tag);
$scope.fullData = $scope.showData;
$scope.filterData(customFilter);
});
}
Do not forget to inject $q as dependency injection.
I have a function that loops through in indeterminate number of items and does an asynchronous call on each one to get additional data (the content of html template files). The callback does some checking. The resulting function should be thenable. $q is injected earlier, this code is part of a factory.
function searchHelpTopics(topics, searchPhrase) {
if (topics == null || topics.length == 0) return "No search results";
var results = [];
var promises = [];
for (var i = 0; i < topics.length; i++) {
var templateURL = topics[i].URL;
var topic = topics[i];
if (topics[i].HelpTopicId != "Search") {
var promise = $templateRequest(templateURL).then(function (template) {
var text = HTMLToText(template, true);
// do the search
if (text.indexOf(searchPhrase) > -1) {
if (text.length > 50) text = text.substring(0, 50);
var result = {};
result.title = topic.Title;
result.excerpt = text;
result.helpID = topic.HelpTopicID;
results.push(result);
}
});
promises.push(promise);
}
}
return $q.all(promises).then(function () {
return results;
})
The problem here is that the for loop does not wait for the callbacks obviously and so the topic being used by the callback is not the correct one. I need a way to pass topic into the callback on each loop.
Because JS has only function scope you can rewrite your code to use function instead of 'for' loop (which is usually better).
To do that you can use JS built-in forEach (which is available starting from version 1.6 so almost for all browsers) or good functional style libraries like underscore.js or lodash.js.
Or even better - to use Array.map and Array.filter - see the code
function processTemplate(topic, template) {
var text = HTMLToText(template, true);
// do the search
if (text.indexOf(searchPhrase) < 0) {
return;
}
if (text.length > 50) {
text = text.substring(0, 50);
}
return {
title: topic.Title,
excerpt: text,
helpID: topic.HelpTopicID
};
}
function searchHelpTopics(topics, searchPhrase) {
if (!topics || topics.length === 0) {
return "No search results";
}
var promises = topics
.filter(function(topic) { return topic.HelpTopicId !== "Search"; })
.map(function(topic) {
return $templateRequest(topic.URL).then(processTemplate);
});
return $q.all(promises)
.then(function (results) {
return results.filter(function (result) {
return result; // filters out 'undefined'
});
});
}
The is not a complete solution but enough to indicate how it works
somefactory.getHelpTopics().then(function (topics) {
somefactory.searchHelpTopics(topics, searchText).then(function (searchResults) {
vm.searchResults = searchResults;
vm.helpID = "Search";
});
});
--- some factory functions ----
function searchHelpTopics(topics, searchPhrase) {
if (!topics || topics.length === 0) return "No search results";
var promises = topics
.filter(function (topic) { return topic.HelpTopicId !== "Search"; })
.map(function (topic) {
return $templateRequest(topic.URL).then(function (template) {
return searchHelpTemplate(template, topic, searchPhrase);
});
});
return $q.all(promises).then(function (results) {
return results.filter(function (result) {
return result; // filters out 'undefined'
});
});
}
function searchHelpTemplate(template, topic, searchPhrase) {
var text = HTMLToText(template, true);
// do the search
if (text.indexOf(searchPhrase) < 0 && topic.Title.indexOf(searchPhrase) < 0) {
return;
}
if (text.length > 50) {
text = text.substring(0, 50);
}
return {
title: topic.Title,
excerpt: text,
helpID: topic.HelpTopicId
};
}
We are constantly getting false positive issues from our JavaScript plugins regarding the function complexity and function length rules.
The reason is that we have functions that are written inside function and the outer functions get the issues.
I understand that technically the complexity looks at everything,
but isn't there a way of getting the plugin to look only at the functions themselves?
(other than marking it as false positive)
Server version 4.5.6
JavaScript plugin version 2.9
There is a complexity issue of rule "javascript:FunctionComplexity" (complexity=25) for the redeployCtrl function.
This is the code, as you can see the actual complexity is from the inner functions.
is there a way around this other than marking the issue as false positive (and losing the complexity issue for the inner functions) or writing a custom rule?
thanks.
function redeployCtrl($scope, utilService, $filter, $location, generalSettings, $uibModalInstance, $uibModal, $timeout,scheme) {
$scope.openStart = openStart;
$scope.isSubmitable = isSubmitable;
$scope.ipCheckbox = ipCheckbox;
$scope.deploy = deploy;
$scope.init = init;
$scope.cancel = cancel;
function init() {
$scope.scheme = scheme;
$scope.loading = 'false';
$scope.envSchemes = [];
$scope.isPermanent = false;
$scope.permanent = {};
$scope.scheme.Scheme.Description = null;
$scope.scheme.Scheme.ExpTime = null;
var max = generalSettings.CalendarEndDate;
$scope.maxDate = new Date();
$scope.maxDate.setMonth($scope.maxDate.getMonth() + max);
$scope.minDate = new Date();
$scope.minDate = $scope.minDate.setDate($scope.minDate.getDate() + generalSettings.MinExpirationDate);
$scope.dateOptions = {
'year-format': 'yyyy',
'starting-day': 1
};
utilService.post(generalSettings.serverPath + 'envscheme/ListSupervisors/', { })
.then(function (data) {
$scope.supervisors = data;
}).catch(function (data) {
utilService.setError(data.ExceptionMessage, "Failed to retrieve data", "img_error");
});
utilService.post(generalSettings.serverPath + 'envscheme/ListPermReasons/', { })
.then(function (data) {
$scope.permReasons = data;
}).catch(function (data) {
utilService.setError(data.ExceptionMessage, "Failed to retrieve data", "img_error");
});
}
function openStart() {
$timeout(function () {
$scope.startOpened = true;
});
}
function deploy(scheme, isPermanent) {
if (isPermanent) {
scheme.Scheme.ExpTime = '01/01/9999';
scheme.Scheme.ApprovedBy = $scope.permanent.approvedBy;
if ($scope.permanent.mainReason === 'Other') {
scheme.Scheme.Reason = $scope.permanent.customReason;
} else {
scheme.Scheme.Reason = $scope.permanent.mainReason;
}
} else {
$scope.scheme.Scheme.ExpTime = utilService.getFormattedDate($scope.scheme.Scheme.ExpTime);
}
$scope.loading = 'true';
utilService.post(generalSettings.serverPath + 'envscheme/ReCreateEnv', scheme)
.then(function (data) {
if (data.Success) {
utilService.alertAmpm("Deploy started successfuly", "Info", "img_information");
$location.path("/MyEnvironments");
}
else {
utilService.alertAmpm(data.Reason, "Failed to Re-Deploy", "img_error");
$scope.loading = 'false';
}
if (data.Reason.indexOf("Session was not found") < -1) {
sessionStorage.clear();
$scope.loading = 'false';
}
}).catch(function (data) {
utilService.setError(data.ExceptionMessage, "Failed to Re-Deploy", "img_error");
$scope.loading = 'false';
});
}
function isSubmitable(invalid, modules) {
if (!invalid) {
for (var i = 0; i < modules.length; i++) {
if (modules[i].ipchkBox) {
if (!modules[i].OS.Parameters.IP) {
return true;
}
}
}
return false;
}
return true;
}
function ipCheckbox(checkBox, name) {
if (!checkBox) {
var name1 = "ipText" + name;
$('[name=' + name1 + ']').val('');
$scope.scheme.Scheme.modules[name].OS.Parameters = new Object();
}
}
function cancel() {
$uibModalInstance.dismiss('cancel');
}
Roy.
These rules force the coding with less nested functions. They ignore some cases like IIFE or practices accepted in some frameworks (AMD, Angular). But that's obviously is not your case.
So if you think that this coding practice is not for you, the only thing you can do is to disable the rules (and may create custom rules counting only lines you want).