Managing service callbacks from controller using promises in AngularJS? - javascript

I have to manage the callback when calling a service function from a controller. My idea is to wrap the service functionality in a promise but then I can't reference the service function from the controller directly. Instead I have to create another function to handle the view events.
function exampleSrv($q) {
this.exampleFn = function() {
var q = $q.defer();
// Do something
q.resolve();
return q.promise;
};
}
function exampleCtrl(exampleSrv) {
this.exampleFn = exampleSrv.exampleFn;
/* This works but I want to avoid this if possible
this.clickHandler = function() {
this.exampleFn()
.then(function() {
console.log('yay');
})
};
*/
/* And instead do something like this but as a reference not as a call
this.exampleFn()
.then(function() {
console.log('yay');
})
*/
}
Is there a better approach to do this?
Example:
http://plnkr.co/edit/jg5yoC?p=info

In short, no, there's no better approach to this. In fact this is the advised manner to tackle such problems.

Actually, you can try something like this: (I am having plunker issues otherwise would have created one)
// Example Service
function exampleSrv($q) {
this.exampleFn = function() {
var q = $q.defer();
// Do something
q.resolve();
return q.promise.then(function() {
return {
"data": "12345"
};
});
};
}
// Example Controller
function exampleCtrl(exampleSrv) {
var ctrl = this;
exampleSrv.exampleFn().then(function(data){
ctrl.exampleFn = data;
});
/* This works but I want to avoid this
this.clickHandler = function() {
this.exampleFn()
.then(function() {
console.log('yay');
})
};
*/
/* And instead do something like this
this.exampleFn()
.then(function() {
console.log('yay');
})
*/
}
angular.module('example', [])
.service('exampleSrv', exampleSrv)
.controller('exampleCtrl', exampleCtrl);
Then in the HTML markup, you can do this:
<!DOCTYPE html>
<html ng-app="example">
<head>
<script data-require="angular.js#1.2.14" data-semver="1.2.14" src="http://code.angularjs.org/1.2.14/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="exampleCtrl as example">
<!-- bind value directly from service -->
{{example.exampleFn}}
</body>
</html>
This way, you don't need an extra controller function and can take service data directly to your markup. Hopefully this is what you were looking for. Good luck.

Related

implementation of global variables in an HTML document with Javascript tags of different types

The situation : I use a script (a) in an HTML document to be able to use a particular SDK. Then I use a second script (b) basic to be able to create a Kendo UI table.
My problem : I try to pass data from script (a) to script (b) via global variables but it doesn't work, what can I do?
Info that might help you:
my document is a form framed by tags
I use Camunda. The first script allows me to use the SDK to retrieve the ID of the instance associated with the form being processed. (but I don't think this is the crux of the problem)
I assume that both scripts are read at the same time by the browser, and that's why script (b) can't read the variable simply because it is not yet created in script (a).
The code :
<script type="text/javascript" src="http://localhost:8080/camunda/app/tasklist/scripts/kendo.all.min.js"></script>
<script cam-script type="text/form-script">
var taskService = camForm.client.resource('task');
var processInstanceId = null;
var result = null;
taskService.get(camForm.taskId, function(err, task) {
//alert(JSON.stringify(task));
debugger;
processInstanceId = task.processInstanceId;
$.get("http://localhost:8080/engine-rest/process-instance/"+processInstanceId+"/variables", function(result) {
debugger;
window.alert("coucou");
console.log(result.JsonWeightSetpoints.value);
});
debugger;
console.log(result.JsonWeightSetpoints.value);
debugger;
});
</script>
<script type="text/javascript">
console.log(result.JsonWeightSetpoints.value);
//this is where I implement the Kendo UI grid
</script>
<div id="grid"></div>
I cannot read the content of the result variable in script (b) because it is not defined.
How do I do this?
Custom events solution:
<script type="text/javascript" src="http://localhost:8080/camunda/app/tasklist/scripts/kendo.all.min.js"></script>
<script cam-script type="text/javascript">
var taskService = camForm.client.resource('task');
var processInstanceId = null;
var result = null;
taskService.get(camForm.taskId, function(err, task) {
//alert(JSON.stringify(task));
debugger;
processInstanceId = task.processInstanceId;
$.get("http://localhost:8080/engine-rest/process-instance/"+processInstanceId+"/variables", function(result) {
debugger;
window.alert("coucou");
console.log(result.JsonWeightSetpoints.value);
// the value is available here, we now can trigger an event and send it
document.dispatchEvent(new CustomEvent("handler", {
detail: { value: result.JsonWeightSetpoints.value }
}));
});
debugger;
console.log(result.JsonWeightSetpoints.value);
debugger;
});
</script>
<script type="text/javascript">
console.log(result.JsonWeightSetpoints.value);
//this is where I implement the Kendo UI grid
// event listener, this would get executed only when we want
document.addEventListener("handler", function(event) {
// write you logic here
console.log(event.detail.value);
});
</script>
<div id="grid"></div>
useful resources:
MDN: Creating and triggering
events
Introducing asynchronous JavaScript

AngularJS: How can I modify service in a document.onload?

I have a strange situation (you can read about the context here. I'm not sure that the answer to this question will answer the question in the link, hence two questions.), where I'd like to modify an AngularJS service after the framework has already been loaded. Here's some code we'd like to do:
<script>
document.onload = function () {
angular.module('common')
.config(function ($provide) {
$provide.factory("$exceptionHandler", function () {
return function (exception) {
throw exception;
};
});
});
}
</script>
This works fine when it's not wrapped in a document.onload. But when it's put in an onload, it doesn't seem to have any effect. How can I modify a service in a document.onload?
For what it's worth, I'm on angular 1.2.
This worked when we tried it:
<script>
window.onload = function () {
angular.element(document.body).injector().invoke(function($log) {
$log.error = function(message) {
throw new Error(message)
};
});
}
</script>

AngularJs promise in forEach

I have method for getting data from server.
And I use it in foreach, and after it need bind him to $scope variable.
Like this:
var qualityMix = [];
var engagementMix = [];
angular.forEach(versions, function (versions) {
qualityMix.push(qualityScoreByTimeWithAppVerPromise(versions.version));
engagementMix.push(engagementByTimeWithAppVerPromise(versions.version));
});
$scope.qualityScoreByTimeMix = function () {
return $timeout(function () {
return $q.all(qualityMix).then(function (data) {
return {series: data};
});
});
};
$scope.engagementTimeMix = function () {
return $q.all(engagementMix).then(function (data) {
return {series: data};
});
};
qualityScoreByTimeWithAppVerPromise and engagementByTimeWithAppVerPromise it is functions for getting data from server. Then $scope.engagementTimeMix and $scope.qualityScoreByTimeMix need return functions with promise (is okay).
This code working but not always, some times I catch exceptions $scope.xxx is not a function.
I don't know how to fix it. Help me please. Thanks a lot!
UPD
It is code for build charts.
<div class="section">
<highchart id="mix_quality_score_by_time" type="area" data="qualityScoreByTimeMix"
chart-style="qualityScoreMixChartStyle"></highchart>
</div>
And my directive I invoke in other page, like this:
<compare-versions id="compare_versions_panel" start-day="timeFilter.startDay()"></compare-versions>
$scope.xxx is not a function
I mean what I catch message in chrome console what
$scope.engagementTimeMix and $scope.qualityScoreByTimeMix it not a function
You can use ng-if and draw graph when you already have value
example:
<div class="section" ng-if="qualityScoreByTimeMix">
<highchart id="mix_quality_score_by_time" type="area" data="qualityScoreByTimeMix" chart-style="qualityScoreMixChartStyle"></highchart>
</div>

Durandal - prevent binding cause issue with compositionComplete of subViews

I work in Durandal-project.
At my project, I need to control the binding-time. i.e, I want to prevent the binding, and do it manually when I want.
define(function organizationView(require) {
var organizationDetails = require('views/organization/organizationDetails');
function myVM() {
var vm = {
organizationDetails: new organizationDetails(),
binding: function () { return { applyBindings: false } }
};
http.get(myUrl).done(function initLookupList(lookup) {
try {
//my code...
that.binding = function () { return { applyBindings: true }; };
binder.bind(that, $('#organization')[0], that, that);
}
catch (err) {
global.treatError(err);
}
});
return vm;
}
return myVM;
});
HTML side:
<div data-bind="compose: { model: organizationDetails, view:'views/organization/organizationDetails.html'}"></div>
my problem is: Durandal not arrive to compositionComplete function of the sub view (organizationDetails)!!!
If I not try control bindings-time, i.e. if I cancel the code: "apply-binding=false" frp, the parent view- it works well.
But I must do it...So what can I do?
You can use parent module's compositioncomplete function.
e.g.
in "shell" module you are composing "nav" view, than you can write binding logic in "shell" compositioncomplete function.

Overriding a jQuery Core function in javascript - getJSON

I am trying to override the getJSON function in jQuery to provide additional params and then call the original getJSON. I am fairly unfamiliar with JavaScript and have scraped this together from other similar examples. Most of the examples I have seen override the behavior from a function in the jQuery.fn namespace. Could someone help me by telling me what I am doing wrong?
<html>
<head>
<script type="text/javascript" src="./js/jquery-1.6.4.min.js"></script>
<script type="text/javascript">
(function($){
var _old = $.getJSON;
$.getJSON = function(){
alert("Calling overridden getJSON");
return _old.apply(this,arguments);
};
})(jQuery);
$(document).ready(function() {
try {
$(this).getJSON('ajax/test.json', function(data) {
var items = [];
alert('done');
});
}
catch (err)
{
alert(err.message);
}
});
</script>
</head>
<body>
</body>
</html>
You need to call $.getJSON, not $(foo).getJSON;
$.getJSON('ajax/test.json', function(data) {
var items = [];
alert('done');
});

Categories