AngularJS Help - User / Data driven UI Load data before finishing controller - angularjs

So I have searched for multiple results online through StackOverflow and haven't really found the answer I am looking for. I am trying put together my main UI page with my AngularJS controller. What I want to accomplish is sort of a Synchronous call that will load all the user data from multiple queries as well as data driven nodes before the main UI page is actually completely loaded. Some of these queries take 2-3 seconds and I need them to finish before the user starts playing/seeing the UI.
Basically what I want to do is the following:
1) Person navigates to home page
2) User Data is Loaded
3) User Data drives data driven UI design
4) Fill out UI with ng-bind values
5) UI now finishing loading for the user to see
Note I am fine with a loading screen, don't really have
Small Example:
http://plnkr.co/edit/9W8wZX8PhrSzv7KE8IEt
<!DOCTYPE html>
<html ng-app="myApp" ng-controller="myCtrl">
<head>
</head>
<body>
<p><u>Username:</u></p>
<p ng-bind="username"></p>
<p><u>Completed in Order:</u></p>
<p ng-repeat="order in list">{{order}}</p>
<p><u>Projects:</u></p>
<p ng-repeat="data in datas">{{data}}</p>
<script data-require="angular.js#*" data-semver="1.2.9" src="http://code.angularjs.org/1.2.9/angular.js"></script>
<script src="script.js"></script>
</body>
</html>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, myService) {
$scope.list = [];
console.log('1 - Started Loading myCtrl');
$scope.list.push('1 - Started Loading myCtrl')
myService.getProjects().then(function(response){
//console.log(response);
$scope.datas = response.Result;
$scope.list.push('2 - getProjects Complete');
});
myService.getUsername().then(function(response){
//console.log(response);
$scope.username = response.Result;
$scope.list.push('3 - getUsername Complete');
});
//I don't want this to run until all the data is loaded
$scope.list.push('4 - Finished Loading myCtrl');
});
app.factory('myService', function($http) {
return{
getProjects : getProjects,
getUsername : getUsername
}
function getProjects(){
return $http.get('project.txt')
.then(getProjectsComplete)
.catch(getProjectsFailed);
function getProjectsComplete(response) {
return response.data;
}
function getProjectsFailed(error) {
console.log('XHR Failed for getProjectsFailed.' + error.data);
}
}
function getUsername(){
return $http.get('username.txt')
.then(getUsernameComplete)
.catch(getUsernameFailed);
function getUsernameComplete(response) {
return response.data;
}
function getUsernameFailed(error) {
console.log('XHR Failed for getUsernameFailed.' + error.data);
}
}
});
My Sample Files: project.txt
{
"Completed": true,
"Status": true,
"ExceptionType": "",
"ExceptionMessage": "",
"StartTime": "2016-12-16T14:19:17.7066714-05:00",
"EndTime": "2016-12-16T14:19:20.7486909-05:00",
"Result": [
"Project1",
"Project2",
"Project3",
"Project4"
]
}
Sample File: username.txt
{
"Completed": true,
"Status": true,
"ExceptionType": "",
"ExceptionMessage": "",
"StartTime": "2016-12-16T14:30:53.354957-05:00",
"EndTime": "2016-12-16T14:30:53.354957-05:00",
"Result": "IamBillyBob"
}
The UI Shows like this:
Username:
IamBillyBob
Completed in Order:
1 - Started Loading myCtrl
4 - Finished Loading myCtrl
3 - getUsername Complete
2 - getProjects Complete
Projects:
Project1
Project2
Project3
Project4
I want it to change to this and always load in this order 100% of the time:
Completed in Order:
1 - Started Loading myCtrl
2 - getProjects Complete
3 - getUsername Complete
4 - Finished Loading myCtrl

Related

Angular $http fails to return coherent cache

I have a problem where a page has two components but only one of them is fully rendered.
The problem seem to be related to $http. I have a angular project where I need to construct a page based on RESTful API. The pages are such that I can expect multiple requests for the same data. At the moment, the set of requests are not behaving correctly.
For the sake of the argument (and also because it is a use case), the following page makes the same request twice.
game.html:
<html ng-app="prvdApp">
<head>
<meta charset="utf-8">
<base href="/">
<title>Providence</title>
<script src="/js/angular-1.6.2.js"></script>
<script src="/data-access/data-access.service.js"></script>
<script src="/score-info/score-info.component.js"></script>
<script src="/js/game.js"></script>
</head>
<body>
<div ng-controller="gameController">
<score-info game-id="8000"></score-info>
<score-info game-id="8000"></score-info>
</div>
</body>
game.js:
angular.module('prvdApp', [
'scoreInfo',
'drivesInfo' ]);
angular.
module('prvdApp').
controller('gameController', function() {
});
score-info.component.js:
angular.module('scoreInfo', [
'dataAccess'
]);
angular.
module('scoreInfo').
component('scoreInfo', {
templateUrl : '/score-info/score-info.template.html',
controller : function ScoreInfoController(dataAccess) {
self = this;
self.$onInit = function() {
dataAccess.game(self.gameId).then(function(game) {
self.game = game;
});
}
},
bindings : {
gameId : '<'
}
});
score-info.template.html:
<div>
Data available: {{ $ctrl.game != undefined }}
</div>
data-access.component.js:
angular.module('dataAccess', []);
angular.
module('dataAccess').
service('dataAccess',
function DataAccessService($http, $q) {
self = this;
self.game = function(game_id) {
var url = '/api/game/' + game_id;
return $http.get(url, { cache: true}).then(function(response) {
return response.data;
});
}
});
The behaviour is as follows:
The page renders with the content:
Data available: false
Data available: false
After some hundreds of milliseconds the $http -request finishes, the page is updated to the following state where only the latter component is updated.
Data available: false
Data available: true
It should be noted that the behaviour is the same even if the two components are of different types with different controllers, etc.

How to bind remote JSON data to a Polymer vaadin-grid?

First time using this web component... I'm able to bind JSON data in a var to a vaadin-grid (w/ polymer 1.0), but am missing something basic about getting the JSON data from a url into the grid.
Here's the most simple example I could create, that worked with hard-coded JSON and now have used some of the examples from the Vaadin website to attempt to pull the data from a URL.
<head>
// import statements same as in my example that works with hard coded JSON
<script>
function getJSON(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
callback(JSON.parse(xhr.responseText));
}
};
xhr.open('GET', url, true);
xhr.send();
}
</script>
</head>
<body>
<h2>Vaadin Grid - example </h2><br>
<vaadin-grid selection-mode="multi">
<table>
<col name="name">
<col name="city">
</table>
</vaadin-grid>
<script>
var grid = grid || document.querySelector('vaadin-grid');
HTMLImports.whenReady(function() {
grid.items = function(params, callback) {
var url = 'https://.../simple-data.json';
getJSON(url, function(data) {
callback(data[0]);
});
};
});
</script>
And simple-data.json URL returns this:
[ { "name": "Jose Romero", "city": "Monteray" }, { "name": "Chuy Diez", "city": "Los Angeles" }, { "name": "Inez Vega", "city": "San Diego" } ]
Where am I going wrong? Thanks in advance.
Binding is easily done using the Polymer 1.0 iron-ajax component. Here's the working code:
<head>
// import statements same as in my example that works with hard coded JSON
<link rel="import" href="iron-ajax/iron-ajax.html">
<link rel="import" href="vaadin-grid/vaadin-grid.html">
</head>
<body>
<h2>Vaadin Grid - working example </h2><br>
<template is="dom-bind">
<iron-ajax
auto
url = "http://hostname/.../simple-data.json"
handle-as="json"
last-response="{{gridData}}" ></iron-ajax>
<vaadin-grid selection-mode="multi" items="{{gridData}}">
<table>
<col name="name">
<col name="city">
</table>
</vaadin-grid>
</template>
<script>
</script>
</body>
I still would like to learn how it's done using the JavaScript code in the Vaadin documentation Remote Data Any tips?
Answering my own question again: to bind JSON to a vaadin-grid using JavaScript instead of using the Polymer iron-ajax component simply add this script section to the bottom of the body. It adds an event listener for WebComponentsReady.
<script type="text/javascript">
window.addEventListener('WebComponentsReady', function() {
var grid = document.querySelector('vaadin-grid');
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var json = JSON.parse(xhr.responseText);
grid.items = json;
}
}
};
xhr.open('GET', 'http://<your_url>', true);
xhr.send();
});
</script>
For others getting started with vaadin Polymer components they have a series of very short, but excellent tutorials - search YouTube for "vaadin elementary school" to find them.

Badge on app icon for Android doesn't show even after implementing ngCordova (cordova-plugin-badge) and phonegap-plugin-push

I will really appreciate if anyone can help me with this issue that has been bugging me for days.
I have a hybrid app created using the Ionic framework, which I have implemented push notifications on (via phonegap-plugin-push). The push notifications work fine, but what I want is for the push notification (i.e. GCM payload) to send a badge count/number over to the application, and the application will take that count/number and displays it as a badge beside the app icon. My code works perfectly for iOS devices given that badges are already inbuilt, but I have difficulties with implementing the same idea (badges) on the Android platform.
I am aware that due to badges not being inbuilt into the Android platform, some devices might not be supported, but at least I want it to work for some devices (i.e. Samsung, Sony). I have done a lot of research, most prominently:
cordova-plugin-badge (https://github.com/katzer/cordova-plugin-badge) which stated in the documentation is supposed to work for both iOS and certain Android devices, but it doesn't work on any Android devices at all for me. Note that the Android devices I have been testing on are emulators from Genymotion, which I have set up Google Play Services on and are able to receive push notifications and function almost like a real device, will that be an issue?
ShortcutBadger (https://github.com/leolin310148/ShortcutBadger) which only has documentation for native Android implementation and supposedly utilised by cordova-plugin-badge as stated above to extend the support to hybrid Android apps, but this has been unable to help me at all.
My index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="css/style.css" rel="stylesheet">
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="lib/ionic-platform-web-client/dist/ionic.io.bundle.min.js"></script>
<script src="js/ng-cordova.js"></script>
<script src="cordova.js"></script>
<script src="js/app.js"></script>
</head>
<body ng-app="starter">
<ion-pane>
<ion-header-bar class="bar-stable">
<h1 class="title">Trade Deals</h1>
</ion-header-bar>
<ion-content ng-controller="badgeController">
<div>Number of deals pending now: </div>
<div class="deals"></div>
<button class="button" ng-click="setBadge(10)">Set badge 10</button>
<button class="button" ng-click="hasPermission()">Show permission</button>
<button class="button" ng-click="get()">Get badge count</button>
<button class="button" ng-click="clear()">Clear badge count</button>
<button class="button" ng-click="increase()">Increase by 1</button>
<button class="button" ng-click="decrease()">Decrease by 1</button>
</ion-content>
</ion-pane>
</body>
</html>
My app.js:
angular.module('starter', ['ionic', 'ngCordova'])
/*
* do a ionic.push register() every time the app launches for the first time
* so that it is guaranteed that there is always a valid device token for GCM/APNS
*/
.run(function($ionicPlatform, $cordovaBadge) {
$ionicPlatform.ready(function() {
console.log("Device platform is "+device.platform);
var push = new Ionic.Push({
"debug": true,
"onNotification": function(notification) {
console.log("notification received!!!");
var payload = notification.payload;
var payloadStr = JSON.stringify(payload, null, 4);
var notiStr = JSON.stringify(notification, null, 4);
console.log("notification: "+notiStr);
var countIndex = notiStr.indexOf("count"); // extracting badge count from the GCM payload
var badgeIndex = countIndex + 9;
var badgeNo;
if (!isNaN(notiStr[badgeIndex+1])) {
badgeNo = notiStr.substr(badgeIndex,badgeIndex+2);
}
else {
badgeNo = notiStr[badgeIndex];
}
if (device.platform == "Android") {
$cordovaBadge.set(badgeNo);
}
},
"onRegister": function(data) {
console.log(data.token);
},
"pluginConfig": {
"android": {
"sound": "true",
"badge": "true",
"icon": "icon",
"iconColor": "lime"
},
"ios": {
"alert": "true",
"badge": "true",
"sound": "true"
},
}
});
push.register(function(token) {
console.log("My Device token:",token.token);
//window.alert("The token is "+token.token);
push.saveToken(token); // persist the token in the Ionic Platform so that it doesn't change on multiple launches
});
$cordovaBadge.get().then(function(badge) {
document.querySelector(".deals").innerHTML = badge;
});
});
})
.controller("badgeController", function($scope, $ionicPlatform, $cordovaBadge) {
console.log("inside badgeController");
$ionicPlatform.ready(function() {
$ionicPlatform.on('resume', function() {
$cordovaBadge.get().then(function(badge) {
document.querySelector(".deals").innerHTML = badge;
});
});
//$cordovaBadge.configure({autoClear: true}); // configure to clear all notifications whenever user opens the app
$scope.setBadge = function(value) {
console.log("inside setBadge");
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.set(value);
window.alert("Badge count is "+value);
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
$scope.hasPermission = function() {
console.log("inside hasPermission");
$cordovaBadge.hasPermission().then(function(result) {
window.alert("User has permission: "+result);
console.log("device has permission");
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
$scope.get = function() {
console.log("inside get");
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.get().then(function(badge) {
if (badge>=0) {
document.querySelector(".deals").innerHTML = badge;
}
})
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
$scope.clear = function() {
console.log("inside clear");
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.clear();
window.alert("Cleared badge count");
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
$scope.increase = function() {
console.log("inside increase");
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.increase();
window.alert("Increased badge count");
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
$scope.decrease = function() {
console.log("inside decrease");
$cordovaBadge.hasPermission().then(function(result) {
$cordovaBadge.decrease();
window.alert("Good job!");
//window.alert("Decreased badge count");
}, function(error) {
console.log(JSON.stringify(error)); // display error message
});
}
});
});
Also, is the issue that the app icon has to be converted to a widget in order for the badges to work? I am not sure how the cordova-plugin-badge is implemented and the instructions didn't say anything about widgets being needed for Android.
Thank you and any help/tips is appreciated :) I have been troubleshooting this for days and it's rather frustrating.
Stock Android does not offer this functionality at the moment on the standard launcher.
Certain manufacturers (e.g. Samsung notably) have included this functionality into their customised Android launchers. Also some 3rd-party launchers (e.g. Nova Launcher) have included an API to accomplish this.
You may want to check following links for further explaination:
How does Facebook add badge numbers on app icon in Android?
Does Samsung modifies it's Android ROMs to have badges on email and SMS icons?
How to make application badge on android?
Regards

ng-view not updating upon ng-click

I am using ng-view within my Angular application. within index.html I have a button, When I click on this button I am getting the JSON data, however I cant access my updated scope back into my ng-view template. please examine the code below.
<
div class="row" style="display:none;" id="srhBox" ng-controller="SearchController">
<button
data-channelid="" data-relatedtovideoid="" data-videoduration="" data-videotype="" data-keyword="{{keyword}}"
ng-click="search($event)" class="btn btn-default" type="submit">
</div>
Here is controller
angular.module('kZoneApp').controller('SearchController', ['$location','$scope', 'dataFactory', '$window', '$routeParams', '$rootScope','$http', function ($location,$scope, dataFactory, $window, $routeParams, $rootScope, $http) {
$scope.search = function (evt) {
$location.path("search"); // update ng-view
var keyword = $(evt.currentTarget).attr("data-keyword");
var channelid = $(evt.currentTarget).attr("data-channelid");
var relatedtovideoid = $(evt.currentTarget).attr("data-relatedtovideoid");
var videoduration = $(evt.currentTarget).attr("data-videoduration");
var videotype = $(evt.currentTarget).attr("data-videotype");
var url = 'http://xxxx.com/api/Videos/Search?'
url = url + 'keyword=' + keyword
url = url + '&channelid=' + channelid
url = url + '&relatedtovideoid=' + relatedtovideoid
url = url + '&videoduration=' + videoduration
url = url + '&videotype=' + videotype
$http.get(url).
success(function (data) {
$scope.searchResults = data;
console.log(data) // Yes it shows JSON data
});
}
}]);
and here is code for ng-view template...
<div class="col-md-12 " style="padding-top:5px;">
{{searchResults.nextPageToken}} // This is BLANK
</div>
json....
{
"nextPageToken": "CBkQAA",
"items": [
{
"etag": "\"dhbhlDw5j8dK10GxeV_UG6RSReM/B_XTRBSSmBkwVbCPVJmABe4rJpo\"",
"id": {
"kind": "youtube#video",
"videoId": "n8JEY8PKCcI"
},
"snippet": {
"publishedAt": "2015-06-05T18:51:06.000Z",
"channelId": "UCY48IObMpigEGsBEtfUUepg",
"title": "WWE 2K15 The New Day vs Power Rangers Summer Slam wwe 2k15",
"description": "I created this video with the YouTube Video Editor (http://www.youtube.com/editor)",
"thumbnails": {
"default": {
"url": "https://i.ytimg.com/vi/n8JEY8PKCcI/default.jpg"
},
"medium": {
"url": "https://i.ytimg.com/vi/n8JEY8PKCcI/mqdefault.jpg"
},
"high": {
"url": "https://i.ytimg.com/vi/n8JEY8PKCcI/hqdefault.jpg"
}
},
"channelTitle": "Caqueen520",
"liveBroadcastContent": "none"
}
},..... more items
route config.
$routeProvider
.when('/search', {
templateUrl: 'pages/search.html',
controller: 'SearchController'
})
so {{searchResults.nextPageToken}} is empty, even though console.log clearly shows it has value. what could be causing this.
UPDATE
it seems like the problem is.... I have ng-controller="SearchController" for my button and then i am loading the VIEW (ng-view) using the routes, so angular does not update two controllers with same name on the same page....it updates the first controller & ignores the second one.
Though $http takes care of running digest cycle which takes care of two way biding, try adding a timeout using $timeout because it also runs the digest cycle.
$http.get(url)
.success(function (data) {
$timeout(function () {
$scope.searchResults = data;
console.log(data) // Yes it shows JSON data
}, 100);
});
As per your route config, /search view uses the same controller SearchController. So when you load the /search view using $location.path('/search') the controller is reinitialized so $scope.searchResults will be undefined. You will have to have to search login inside a different controller and use that controller in the route config.
OR you can have a hidden partial view and show it only when you have the searchResults using ng-if directive.
So in the main view have this html
<div ng-if="searchResults" class="col-md-12 " style="padding-top:5px;">
{{searchResults.nextPageToken}} // This is BLANK
</div>
And remove the $location.path('/search') from $scope.search method in the SearchController.

window.postMessage between iframe and its parent with Angular: does anyone have a working example?

Does anyone have a working example of how to send and receive window.postMessage() calls in angular? I found the ng-post-message module on github and ngmodules, but I look at that code and it doesn't make a whole lot of sense to me and the documentation is lacking a working example.
Edit: to add my failed attempt
The view
<div simulation-host element="thing in things"></div>
</div>
<div id="debugConsole">
<h1>MESSAGE CONSOLE</h1>
<p id="debugText"></p>
</div>
The model
$scope.things =
[
{
"location" : "Foobar",
"resource" : $sce.trustAsResourceUrl("http://external.domain:14168/Foo/Bar"),
"title" : "Launch"
}
];
My attempt at a directive
var simulationFrameHost = angular.module('proxy.directives', []);
simulationFrameHost.config(function ($sceDelegateProvider){
//URL Regex provided by Microsoft Patterns & Practices.
$sceDelegateProvider.resourceUrlWhitelist(['^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&%\$#_]*)?$','self']);
});
simulationFrameHost.directive('simulationHost', ['$window',function($window) {
return {
retrict: 'ACE',
transclude: 'element',
replace: true,
scope: true,
template: [
'<ul>',
'<li>',
'<span>',
'<a href="#">',
'{{thing.location}}',
'</a>',
'</span>',
'<messenger>',
'<iframe ng-src="{{thing.resource}}" />',
'</messenger>',
'</li>',
'</ul>'
].join(''),
compile: function (tElement, tAttrs, transclude) {
var interval;
var show = function(msg)
{
var debugText = document.getElementById("debugText");
if(debugText){
debugText.innerHTML += msg + "<br/>";
}
};
var rpt = document.createAttribute('ng-repeat');
rpt.value = tAttrs.element;
console.log(tAttrs.element);
tElement[0].children[0].attributes.setNamedItem(rpt);
$(tElement[0].children[0].children[0].children[0]).on("click", function(event){
console.log(event);
var iframe = tElement[0].children[0].children[1].children[0].contentWindow;
show("Initiating connection with: " + event.currentTarget.host);
var message = {
action: 'syn',
param: 'connection'
};
interval = setInterval(function(){
//*****************************************
iframe.postMessage(JSON.stringify(message), 'http://'+ event.currentTarget.host);
//*****************************************
}, 500);
return false;
});
}
}
}]);
Working legacy code that I am trying to adapt to Angular
Note that this code uses a popup rather than an iframe; ran into the complication that IE's postMessage between windows is broken so have to fall back to iframe.
Markup
<body>
<div id="debugConsole">
<h1>MESSAGE CONSOLE</h1>
<p id="debugText"></p>
</div>
<h1>This is a test</h1>
<ul>
<li>
<a href= "http://external.domain:14168/Foo/Bar" target="_blank" ><p>Foobar</p></a>
</li>
</ul>
<script src="js/jquery-1.10.2.min.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-animate/angular-animate.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<script src="bower_components/angular-resource/angular-resource.js"></script>
<script src="js/SCORM_API_wrapper.js"></script>
<script src="js/json2.js"></script>
<script src="js/plugins.js"></script>
<script src="js/index.js"></script>
</body>
index.js
$('a').on("click",function(event){
console.log(event);
var pop = window.open(event.currentTarget.href, 'poop');
show("Initiating connection with: " + event.currentTarget.host);
var message = {
action: 'syn',
param: 'connection',
};
interval = setInterval(function(){
pop.postMessage(JSON.stringify(message), 'http://'+ event.currentTarget.host);
}, 500);
return false;
});
$(window).on("message", function(e) {
clearInterval(interval);
var eventData = JSON.parse(e.originalEvent.data);
show("Message received from: " + e.originalEvent.origin);
if(eventData.action) {
switch (eventData.action) {
case 'syn-ack':
ack(e.originalEvent, eventData.param, eventData.value);
break;
case "set":
show("Set request received: " + e.originalEvent.data);
set(eventData.param, eventData.value);
break;
case "get":
show("Get request received: " + e.originalEvent.data);
var value = get(eventData.param);
var response = {
action: "response",
type: "get",
param: eventData.param,
value: value
};
e.originalEvent.source.postMessage(JSON.stringify(response), channel);
break;
}
}
});
In my directive's compile, I'm trying to wire up a click event to the generated anchor tag. I'm trying to get the click to post a message to the iframe, but iframe.postMessage is doing nothing. It just goes off into the nether, and I've been working on this since 10 this morning. My eyes are starting to glaze over : p
Edit: Adding an extension requirement (now that I have functioning code) for a general messaging directive between separate containers, regardless of the container type:
1)iframe to parent
2)window to window (<=yes, I already know this doesn't work in IE)
I had legacy code working that performed window to window messaging by having the window that spawned
the second post a "syn" message to it immediately after creating it. The second window then received the message as a "syn" and stored the sender as a messageHandle so that it could maintain a channel to post return messages then returned a "syn-ack." The originator followed up with an "ack" and the secondary window received the ack and proceeded with its work. (If the ack did not return before the timeout, I logged that the connection had failed and then the secondary window polled on an interval to attempt to restore the connection)
Just came across this post, this may help you.
(function() {
'use strict';
angular
.module('postmessage')
.factory('iFrameMessagingService', iFrameMessagingService);
iFrameMessagingService.$inject = ['$window', '$location', '$rootScope', '$log'];
function iFrameMessagingService($window, $location, $rootScope, $log) {
var service = {
sendMessage : sendMessage
};
activate();
return service;
function activate(){
activateIncomingMessageHandler();
}
function activateIncomingMessageHandler(){
$window.addEventListener('message', function(event){
if (typeof(event.data) !== 'undefined'){
// handle message
}
});
}
function sendMessage(message){
// Dispatch the event.
$log.debug(message);
if($window.parent !== $window){
$window.parent.postMessage(message, '*');
}
}
}
})();
I couldn't get this working with an Angular directive. I pulled a wasted all nighter trying to get this done "The Right Way" and wish I had ejected that idea sooner because my requirements didn't really warrant it. This thing doesn't have to scale because it is purpose build software for providing a messaging proxy between X-Domain systems.
'use strict'
var app = angular.module('domain.system.controllers', ['services.proxy.mine']);
app.controller('ProxyCtrl', ['$scope', '$routeParams', '$window', '$sce', 'MyService',
function ( $scope, $routeParams, $window, $sce, MyService)
{
$($window).on("message", function(e){
var message = JSON.parse(e.originalEvent.data);
if(message.recipient){
switch(message.recipient){
case: "ProxyCtrl":
//handle message;
break;
}
}
}
}
]);
I am 100% interested in a detailed explanation of how to convert this code into a functioning directive.

Resources