Skip to content
This repository has been archived by the owner on Dec 1, 2020. It is now read-only.

Commit

Permalink
Merge pull request #256 from Esri/v2-registry-#255
Browse files Browse the repository at this point in the history
esriRegistry for v2
  • Loading branch information
tomwayson committed Mar 4, 2016
2 parents ce9a17e + ae5e233 commit be35b56
Show file tree
Hide file tree
Showing 17 changed files with 473 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Property binding patterns page [#238](/~https://github.com/Esri/angular-esri-map/p

Added esri-webscene-slides directive and related test, example, and patterns pages [#254](/~https://github.com/Esri/angular-esri-map/pull/254)

Added esriRegistry service and related test, example, and patterns documentation. [#256](/~https://github.com/Esri/angular-esri-map/pull/256)

### Support

Docs site is more mobile friendly [#245](/~https://github.com/Esri/angular-esri-map/pull/245) and shows error message when mobile browsers don't have required support for WebGL [#250](/~https://github.com/Esri/angular-esri-map/pull/250).
Expand Down
4 changes: 3 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ gulp.task('clean', function() {
gulp.task('build-core-js', function() {
return gulp.src([
'src/core/esri.core.module.js',
'src/core/esriLoader.js'])
'src/core/esriLoader.js',
'src/core/esriRegistry.js'])
.pipe(concat('angular-esri-core.js'))
.pipe(gulp.dest('dist'))
.pipe(gulp.dest('site/lib'))
Expand All @@ -65,6 +66,7 @@ gulp.task('build-js', function() {
return gulp.src([
'src/core/esri.core.module.js',
'src/core/esriLoader.js',
'src/core/esriRegistry.js',
'src/esri.map.module.js',
'src/map/EsriHomeButtonController.js',
'src/map/EsriMapViewController.js',
Expand Down
12 changes: 12 additions & 0 deletions site/app/appConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,18 @@
controller: 'PropertyBindingCtrl',
controllerAs: 'vm'
}
}, {
toc: {
title: 'Registry Pattern',
description: 'Shows how to get a reference to the map object by using the registry.',
url: urlPrefixes.templateHref + 'registry-pattern'
},
route: {
path: urlPrefixes.routePath + 'registry-pattern',
templateUrl: urlPrefixes.routeTemplateUrl + 'registry-pattern.html',
controller: 'RegistryPatternCtrl',
controllerAs: 'vm'
}
}]
},
patternsPages: [
Expand Down
45 changes: 45 additions & 0 deletions site/app/examples/registry-pattern.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<style type="text/css">
.esri-view {
max-height: 250px;
}
</style>

<h2>Registry Pattern</h2>

<esri-map-view
map="vm.map"
register-as="myMapView"
view-options="vm.mapViewOptions"
on-create="vm.onMapViewCreated">
</esri-map-view>

<hr>

<div class="web-gl-warning" ng-show="vm.showSceneViewError">WebGL is not supported on your platform/browser.</div>
<esri-scene-view
map="vm.map"
register-as="mySceneView"
view-options="vm.sceneViewOptions"
on-create="vm.onSceneViewCreated"
on-error="vm.onSceneViewError"
ng-hide="vm.showSceneViewError">
</esri-scene-view>

<div ng-controller="AnotherController as anotherCtrl">
<p ng-show="!anotherCtrl.mapViewPoint">
Click the map view to see point X / Y.
</p>
<p id="mapViewClickInfo" ng-show="anotherCtrl.mapViewPoint">
Clicked map view point X: {{ anotherCtrl.mapViewPoint.x }}, Y: {{ anotherCtrl.mapViewPoint.y }}
</p>

<p ng-show="!anotherCtrl.sceneViewPoint">
Click the scene view to see point X / Y.
</p>
<p id="sceneViewClickInfo" ng-show="anotherCtrl.sceneViewPoint">
Clicked scene view point X: {{ anotherCtrl.sceneViewPoint.x }}, Y: {{ anotherCtrl.sceneViewPoint.y }}
</p>
</div>

<p>Learn more about the <a href="/#/patterns/references-to-views">registry pattern</a>.</p>
<p>Based on <a href="https://developers.arcgis.com/javascript/beta/sample-code/get-started-mapview/index.html">this sample</a>.</p>
68 changes: 68 additions & 0 deletions site/app/examples/registry-pattern.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
angular.module('esri-map-docs')
.controller('RegistryPatternCtrl', function(esriLoader, browserDetectionService) {
var self = this;

self.mapViewOptions = {
zoom: 4,
center: [15, 65]
};

self.sceneViewOptions = {
zoom: 4,
center: [15, 65]
};

// load esri modules
esriLoader.require([
'esri/Map'
], function(Map) {
// create the map
self.map = new Map({
basemap: 'streets'
});

// NOTE: This is one way to get a reference to the map or scene view within
// the SAME parent controller, by binding to the on-create callback.
self.onMapViewCreated = function(view) {
self.mapView = view;
// do something with the map view
};
self.onSceneViewCreated = function(view) {
self.sceneView = view;
// do something with the scene view
};

// check that the device/browser can support WebGL
// by inspecting the userAgent and
// by handling the scene view directive's on-error
self.showSceneViewError = browserDetectionService.isMobile();
self.onSceneViewError = function() {
self.showSceneViewError = true;
};
});
})
.controller('AnotherController', function(esriRegistry, $scope) {
// NOTE: This is a way to get a reference to a view in
// a DIFFERENT controller, by setting the register-as attribute
// on the view directive and then using esriRegistry to get the view by name.
var self = this;

esriRegistry.get('myMapView').then(function(res) {
// establish a click listener on the view in the response
res.view.on('click', function(e) {
// set or update the point property that is used in the html template
self.mapViewPoint = e.mapPoint;

// NOTE: $scope.$apply() is needed b/c the view's click event
// happens outside of Angular's digest cycle
$scope.$apply();
});
});

esriRegistry.get('mySceneView').then(function(res) {
res.view.on('click', function(e) {
self.sceneViewPoint = e.mapPoint;
$scope.$apply();
});
});
});
7 changes: 7 additions & 0 deletions site/app/patterns/references-to-views.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ <h2>Getting a Reference to the Map and Scene Views</h2>
scene view objects from a parent controller. This will allow you to
manipulate those objects in ways beyond what is allowed by the
declarative directive API.</p>

<h3>Events</h3>
<p>The map and scene view directives each include both <code>on-create</code>
and <code>on-load</code> events that pass a reference to the underlying map or
Expand Down Expand Up @@ -34,5 +35,11 @@ <h4>On-load</h4>
<ul>
<li><a href="#/examples/webscene-slides">Work with Slides in a WebScene</a></li>
</ul>

<h3>Registry</h3>
<p>We've also included a <a href="/docs/#/api/esri.core.factory:esriRegistry">registry service</a>
that you can use to get a direct reference to a map view or scene view object by setting the
<code>register-as</code> attribute on the map view or scene view directive.
See the <a href="#/examples/registry-pattern">Registry Pattern</a> example.</p>
</div>
</div>
4 changes: 4 additions & 0 deletions site/docs-resources/esri.core.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ The `esri.core` module includes services used by the directives in the {@link es
### Loading Esri Modules

Use {@link esri.core.factory:esriLoader esriLoader} to lazy load the Esri ArcGIS API or to load API modules.

### Getting a Reference to a MapView or SceneView

Use the {@link esri.core.factory:esriRegistry esriRegistry} to store and retrieve Esri MapView or SceneView instances for use in different controllers.
1 change: 1 addition & 0 deletions site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ <h4 class="page-header list-group-category">Patterns</h4>
<script type="text/javascript" src="app/examples/home-button.js"></script>
<script type="text/javascript" src="app/examples/popups.js"></script>
<script type="text/javascript" src="app/examples/property-binding.js"></script>
<script type="text/javascript" src="app/examples/registry-pattern.js"></script>
<script type="text/javascript" src="app/examples/scene-toggle-elevation.js"></script>
<script type="text/javascript" src="app/examples/scene-view.js"></script>
<script type="text/javascript" src="app/examples/search.js"></script>
Expand Down
80 changes: 80 additions & 0 deletions src/core/esriRegistry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
(function(angular) {
'use strict';

/**
* @ngdoc service
* @name esri.core.factory:esriRegistry
*
* @description
* Use `esriRegistry` to store and retrieve MapView or SceneView instances for use in different controllers.
*
* ## Examples
* - {@link ../#/examples/registry-pattern Registry Pattern}
*/
angular.module('esri.core').service('esriRegistry', function($q) {
var registry = {};

return {
_register: function(name, promise) {
// if there isn't a promise in the registry yet make one...
// this is the case where a directive is nested higher then the controller
// needing the instance
if (!registry[name]) {
registry[name] = $q.defer();
}

var instance = registry[name];

// when the promise from the directive is rejected/resolved
// reject/resolve the promise in the registry with the appropriate value
promise.then(function(arg) {
instance.resolve(arg);
return arg;
}, function(arg) {
instance.reject(arg);
return arg;
});

// return a function to "deregister" the promise
// by deleting it from the registry
return function() {
delete registry[name];
};
},

/**
* @ngdoc function
* @name get
* @methodOf esri.core.factory:esriRegistry
*
* @description
* Get the MapView or SceneView instance registered with the given name.
* See {@link esri.map.directive:esriMapView esriMapView} or
* {@link esri.map.directive:esriSceneView esriSceneView}
* for info on how to register a map using the `register-as` attribute.
*
* @param {String} name Name that the view was registered with.
*
* @return {Promise} Returns a $q style promise which is resolved with the view once it has been loaded.
*/
get: function(name) {
// If something is already in the registry return its promise ASAP.
// This is the case where you might want to get a registry item in an event handler.
if (registry[name]) {
return registry[name].promise;
}

// If we dont already have a registry item create one. This covers the
// case where the directive is nested inside the controller. The parent
// controller will be executed and gets a promise that will be resolved
// later when the item is registered
var deferred = $q.defer();

registry[name] = deferred;

return deferred.promise;
}
};
});

})(angular);
21 changes: 20 additions & 1 deletion src/map/EsriMapViewController.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
* Functions to help create MapView instances.
*
* @requires esri.core.factory:esriLoader
* @requires esri.core.factory:esriRegistry
* @requires $element
* @requires $scope
* @requires $q
*/
angular.module('esri.map')
.controller('EsriMapViewController', function EsriMapViewController($element, $scope, esriLoader) {
.controller('EsriMapViewController', function EsriMapViewController($element, $scope, $q, esriLoader, esriRegistry) {
var self = this;

// read options passed in as either a JSON string expression
Expand Down Expand Up @@ -65,6 +67,17 @@
return this.getMapView().then(function(result) {
self.view = new result.view(self.options);

// set up a deferred for dealing with the (optional) esriRegistry
var viewRegistryDeferred = $q.defer();
if (typeof self.registerAs === 'string') {
self.deregister = esriRegistry._register(self.registerAs, viewRegistryDeferred.promise);
$scope.$on('$destroy', function() {
if (self.deregister) {
self.deregister();
}
});
}

if (typeof self.onCreate() === 'function') {
self.onCreate()(self.view);
}
Expand All @@ -75,10 +88,16 @@
self.onLoad()(self.view);
});
}
// handle the deferred that is intended for use with the esriRegistry
viewRegistryDeferred.resolve({
view: self.view
});
}, function(err) {
if (typeof self.onError() === 'function') {
self.onError()(err);
}
// handle the deferred that is intended for use with the esriRegistry
viewRegistryDeferred.reject(err);
});
});
} else {
Expand Down
21 changes: 20 additions & 1 deletion src/map/EsriSceneViewController.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
* Functions to help create SceneView instances.
*
* @requires esri.core.factory:esriLoader
* @requires esri.core.factory:esriRegistry
* @requires $element
* @requires $scope
* @requires $q
*/
angular.module('esri.map')
.controller('EsriSceneViewController', function EsriSceneViewController($element, $scope, esriLoader) {
.controller('EsriSceneViewController', function EsriSceneViewController($element, $scope, $q, esriLoader, esriRegistry) {
var self = this;

// read options passed in as either a JSON string expression
Expand Down Expand Up @@ -68,6 +70,17 @@
return this.getSceneView().then(function(result) {
self.view = new result.view(self.options);

// set up a deferred for dealing with the (optional) esriRegistry
var viewRegistryDeferred = $q.defer();
if (typeof self.registerAs === 'string') {
self.deregister = esriRegistry._register(self.registerAs, viewRegistryDeferred.promise);
$scope.$on('$destroy', function() {
if (self.deregister) {
self.deregister();
}
});
}

if (typeof self.onCreate() === 'function') {
self.onCreate()(self.view);
}
Expand All @@ -78,10 +91,16 @@
self.onLoad()(self.view);
});
}
// handle the deferred that is intended for use with the esriRegistry
viewRegistryDeferred.resolve({
view: self.view
});
}, function(err) {
if (typeof self.onError() === 'function') {
self.onError()(err);
}
// handle the deferred that is intended for use with the esriRegistry
viewRegistryDeferred.reject(err);
});
});
} else {
Expand Down
4 changes: 4 additions & 0 deletions src/map/esriMapView.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
* @param {Function=} on-load Callback for successful loading of the map view.
* @param {Function=} on-error Callback for rejected/failed loading of the map view.
* @param {Object | String=} view-options An object or inline object hash string defining additional map view constructor options.
* @param {String=} register-as A name to use when registering the view so that it can be used by other controllers.
* See {@link esri.core.factory:esriRegistry esriRegistry}.
*/
angular.module('esri.map')
.directive('esriMapView', function esriMapView() {
Expand All @@ -34,6 +36,8 @@

// isolate scope
scope: {
// one-way binding
registerAs: '@?',
// two-way binding
map: '=?',
// function binding for event handlers
Expand Down
Loading

0 comments on commit be35b56

Please sign in to comment.