600 likes | 619 Views
Widgets 101: Customizing and Creating Widgets with the ArcGIS API for JavaScript. JC Franco – @arfncode Matt Driscoll – @driskull. Welcome. Agenda. Short URL: bit.ly/widgets101 About widgets Building blocks Building a widget 3.x 4.x Tips & best practices Resources Q & A. Widgets.
E N D
Widgets 101: Customizing and Creating Widgets with the ArcGIS API for JavaScript JC Franco – @arfncode Matt Driscoll – @driskull
Agenda Short URL: bit.ly/widgets101 About widgets Building blocks Building a widget 3.x 4.x Tips & best practices Resources Q & A
Widgets What? Encapsulated Cohesive Single-purpose pieces of functionality User interface Why? Reusable Interchangeable Modular How? Different frameworks are available Focusing on Dijit
Dojotoolkit Foundation of ArcGIS JavaScript API AMD support Class-based inheritance Internationalization
Dijit Dojo’s UI Library Separate namespace (dijit) Built on top of Dojo Has themes
Asynchronous Module Definition(AMD) Asynchronous loading Web-based solution Lazy loading Fewer globals Dependency handling
define // moduleA.js define(["moduleB"], function (moduleB) { // module API return { _data: 100, calculate: function () { moduleB.calculate(this._data); } }; }); AMDexample require // main.js require(["moduleA"], function (moduleA) { moduleA.calculate(); });
AMDPlugins text "dojo/text!./templates/WikiWidget.html" i18n "dojo/i18n!./nls/WikiWidget",
What you get Lifecycle constructor postMixInProperties buildRendering postCreate startup destroy Events Getters/Setters Property watching dijit/_WidgetBase
Called immediately when widget is created Can be used for initialization Can be used to manipulate widget parameters constructor constructor: function(params) { // initialize private variables this._activeTasks = []; // manipulate user-provided params if (params && params.oldProp { params.newProp = params.oldProp; delete params.oldProp; } }
Called after properties have been mixed into theinstance Can be used to access/alter properties after being mixed in, but beforerendering postMixInProperties postMixInProperties: function() { this.get("inherited"); this._initialTitle = this.title; } Forexample var myWidget = new MyWidget({ title: "myTitle" }, "sample-node"); myWidget.toUppercase(); console.log(myWidget.title); // MYTITLE console.log(myWidget._initialTitle); // myTitle
buildRendering Widget template is parsed and its DOM is available Not attached to the DOM tree buildRendering: function() { this.get("inherited"); if (this.editMode) { // editor added before widget is displayed this._attachEditor(this.domNode); } }
Most widget DOM nodes are ready at this point Widget not attached to the DOM yet Most common point for adding custom logic postCreate postCreate: function(){ this.get("inherited"); // set up eventlisteners // `this.own`disposeshandle this.own( on(this.inputNode,"input", ); whendestroyed this._handleInput) this._activeTasks.push( this._initialize() ); }
startup Called manually or by dojo/parser, initializes all children Recommended point for doing size calculations Must always call when creating widgets programmatically startup: function() { this.get("inherited"); this._resize(); }
Used for teardown logic • By default, destroys top-level support widgets Called manually to trigger widget disposal • All handles registered with this.own get removed destroy destroy: function() { this.get("inherited"); this._activeTasks.forEach(function(process) { process.cancel(); }); }
// widget function startTimer: function() { setInterval(function() { this.emit("tick"); }.bind(this), 1000); } Events timerWidget.on("tick", function() { console.log("timer ticked!"); }); timerWidget.startTimer();
Getters/Setters widget.get("title"); // old widget.set("title", "new"); widget.get("title"); // new
Watch widget.watch("title", function(propName, oldValue, newValue) { console.log( propName + " changed from ", oldValue, " to ", newValue ); }); widget.get("title"); // old widget.set("title", "new"); // "title" changed from "old" to "new"
Codeorganization Keep code modular andorganized
Code organization:HTML Extract HTML to separate file Mix in dijit/_TemplatedMixin Renders HTML based on a template string (use dojo/text plugin) Create DOM node attachments
Code organization:CSS Extract widget-specific styles to separatestylesheet @import widget stylesheet whereverapplicable
/* ./MyWidget.js */ define([ "dijit/_WidgetBase", "dijit/_TemplatedMixin" ], function ( _WidgetBase, _TemplatedMixin ) { return _WidgetBase.createSubclass([_TemplatedMixin], { templateString: "<div style='background-color: chartreuse;'>" + "<label style='font-weight: bolder;'>°˖✧◝(⁰▿⁰)◜✧ "</div>"; }); }); Example:before
Example:after MyWidget.html <div class="my-widget"> <label class="my-widgettext">°˖✧◝(⁰▿⁰)◜✧˖°</label> </div>
Example:after MyWidget.css .my-widget { background-color: chartreuse } .my-widgettext { font-size: 1.5em; }
MyWidget.js Example:after define([ "dijit/_WidgetBase", "dijit/_TemplatedMixin", "dojo/text!./templates/MyWidget.html" ], function ( _WidgetBase, _TemplatedMixin, template ) { return _WidgetBase.createSubclass([_TemplatedMixin], { templateString: template }); });
CSS Useclasses <style> .my-widget{ background-color:chartreuse; } </style> <divclass="my-widget">...</div> and avoid inlinestyles <div style="background-color:chartreuse">...</div>
Accessibility(a11y) Enable your application to be used by everyone Consider other input devices besides the mouse Keyboard Touch Screen reader semantic markup, ARIA roles dijit/a11yclick
Internationalization(i18n) Keep text separate from application logic Support multiple languages Helps ease translation define({ root: ({ "button": "Home", "title": "Default extent" }), "ar": 1, ... "zh-cn": 1 });
DOMmanipulation Here to help... dojo/dom dojo/dom-attr dojo/dom-class dojo/dom-construct dojo/dom-style (used sparingly)
DOMmanipulation Here tohelp... // without `dojo/dom-class` document.getElementById("container-id") .classList.add("round-borders"); // with `dojo/dom-class` domClass.add("container-id", "round-borders");
Use Wikipedia API to geosearch for entries Display results in a list List items should center on the map and display a popup The popup should have a link for more info (wiki page) Preview WikiWidget(requirements)
4.xWidgets Widget Pattern View – the face ViewModel – the brain
View Uses ViewModel APIs to render the UI View-specific logic resides here
ViewModel Core logic of widget resides here Provides necessary APIs for the view to do it's thing No DOM/UI concerns (think data)
Benefits Reusable Testable Logic without UI concerns Framework compatibility
Let's updateWikiWidget Steps
WikiWidget +React Demo
Frameworkintegration Use ViewModels to create custom UIs in the framework of your choice Angular 2– demo React– demo Elm– demo Ember Rene Rubalcava - http://odoe.net/
Use astyleguide Defines rules for consistent code Naming conventions Whitespace Common patterns Etc... Some options Airbnb Google idiomatic jQuery Dojo
Linting (codeanalysis) Highlight issues in your code based on predefined rules JSLint JSHint ESLint
Formatting Format your code based on predefined rules ESLint JS Beautifier
Taskrunners Automate all the things Grunt Gulp
Testing Automated testing helps you catch regressions as you move forward Intern Jasmine QUnit Karma
Features Variables Mixins @import & @extend Allow us to Restyle quickly Theme Write less code Flavors Sass Stylus Less Demo CSSpreprocessors