tag:adamkrasny.svbtle.com,2014:/feedAdam Krasny2015-05-13T18:15:01-07:00Adam Krasnyhttps://adamkrasny.svbtle.comSvbtle.comtag:adamkrasny.svbtle.com,2014:Post/simplify-async-code-with-generators-and-promises2015-05-13T18:15:01-07:002015-05-13T18:15:01-07:00Simplify async code with generators and promises<p>Asynchronous code is a necessary part of life when developing in JavaScript. Why not make it easy on yourself?</p>
<p>Start with promises. They reduce the need for callback functions and practically eliminate nested callbacks. If you aren’t already using them, you should be. My favorite library for promises is <a href="https://github.com/petkaantonov/bluebird">https://github.com/petkaantonov/bluebird</a></p>
<p>Then we have generators. They are a new feature introduced in ES6. You can read more about them here: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*</a></p>
<p>Even when using promises, async code can become unwieldy. Take a look at the following code.</p>
<pre><code class="prettyprint">getUser(id).then(function (user) {
return getCompany(user.companyId).then(function(company) {
return getUser(company.ceoId);
});
});
</code></pre>
<p>Assume id is already set and that all functions return promises. The code will return the user object for the CEO of the original user’s company. Take a look at that same function using generators and <a href="https://github.com/tj/co">https://github.com/tj/co</a>, a helper library.</p>
<pre><code class="prettyprint">co(function *() {
let user = yield getUser(id);
let company = yield getCompany(user.companyId);
return yield getUser(company.ceoId);
});
</code></pre>
<p>Not bad. Generators used with promises gives us code that is nearly identical to async/await. Much easier to follow and read.</p>
<p>If you’re using Bluebird, coroutines provide the same functionality.</p>
<p><a href="https://github.com/petkaantonov/bluebird/blob/master/API.md#promisecoroutinegeneratorfunction-generatorfunction---function">https://github.com/petkaantonov/bluebird/blob/master/API.md#promisecoroutinegeneratorfunction-generatorfunction—function</a></p>
tag:adamkrasny.svbtle.com,2014:Post/start-using-es62015-05-12T16:24:47-07:002015-05-12T16:24:47-07:00Start using ES6<p>JavaScript is the unavoidable language that everyone loves to hate. Unnecessary type coercion, lack of proper class constructs, and dynamic function context are just a few things that are, at best, an annoyance and, at worst, can cause hard to find bugs in your code.</p>
<p>What if I told you there was an easy way to fix most of this frustration?</p>
<p>EcmaScript 6 is the new standard that will drive JavaScript engines. The first update to the language since EcmaScript 5 was standardized in 2009, 6 years ago. That’s around the time of iOS 3 and Android 2.0.</p>
<p><a href="https://babeljs.io/">https://babeljs.io/</a> is a tool that let’s you transpile your ES6 code into ES5. This gives you access to all of the awesome functionality that ES6 introduces. Generators, arrow functions, classes, template strings, destructuring, enhanced object literals, and modules are features that will improve your code and make coding more pleasant.</p>
<p>With node, I’ve found that using the require hook is the way to go. Since ES5 is valid ES6, you can add this to an existing code base and slowly start the migration.</p>
<p>In the browser, a compilation step will be needed before your code is deployed. You can use the CLI or integrate with your preferred build tool.</p>
<p>Check out the official site for further documentation and STOP handicapping your JavaScript with ES5. Prepare yourself for the future and start enjoying JavaScript again.</p>
<p><a href="https://babeljs.io/docs/using-babel">https://babeljs.io/docs/using-babel</a></p>
tag:adamkrasny.svbtle.com,2014:Post/angularjs-simple-reusable-directives2014-04-24T07:40:51-07:002014-04-24T07:40:51-07:00AngularJS: Simple, reusable directives<p>Directives in Angular give you the power to do a lot. Sometimes, you need to do a lot. Most of the time you just need something simple that will get the job done. Here are a few examples of reusable directives that do only what they need to do.</p>
<p>First, a directive that can be applied to a button group. Keep in mind this isn’t restricted to a button group, and if you think creatively, it can come be applied in a lot of places.</p>
<pre><code class="prettyprint"> mod.directive('radioValue', function () {
return {
restrict: 'A',
require: '^ngModel',
scope: {
radioValue: '='
},
link: function (scope, elem, attrs, ngModelCtrl) {
elem.on('click', function () {
scope.$apply(function () {
ngModelCtrl.$setViewValue(scope.radioValue);
});
});
scope.$watch(function() {
return ngModelCtrl.$modelValue;
}, function(newVal) {
elem.toggleClass('selected', newVal === scope.radioValue);
});
}
};
});
</code></pre>
<p>Not impressed? You don’t have to be. Keep it simple. Here’s an example of how this directive would be used.</p>
<pre><code class="prettyprint"><div class='btn-group' ng-model='ctrl.animal'>
<div class='btn' radio-value='"Dog"'>Dog</div>
<div class='btn' radio-value='"Cat"'>Cat</div>
<div class='btn' radio-value='"Pig"'>Pig</div>
</div>
</code></pre>
<p>Full demo: <a href="http://jsfiddle.net/xQCRB/2/">http://jsfiddle.net/xQCRB/2/</a></p>
<p>The beauty of the directive, to me, is that we take advantage of an existing controller and the directive’s ability to require parent controllers to provide mutually exclusive selection on a model value.</p>
<p>Here’s one more simple directive and how it can be used. It’s actually quite similar.</p>
<pre><code class="prettyprint">app.directive('setValueOnClick', function () {
return {
restrict: 'A',
require: '^ngModel',
scope: {
setValueOnClick: '='
},
link: function (scope, elem, attrs, ngModelCtrl) {
elem.on('click', function () {
scope.$apply(function () {
ngModelCtrl.$setViewValue(scope.setValueOnClick);
});
});
}
};
});
</code></pre>
<p>And it’s usage</p>
<pre><code class="prettyprint"><div ng-controller="Controller as ctrl">
<div ng-model='ctrl.number'>
<div class='number' ng-repeat='num in ctrl.numbers' set-value-on-click='num'>{{num}}</div>
</div>
<h2>{{ctrl.number}}</h2>
</div>
</code></pre>
<p>Working example: <a href="http://jsfiddle.net/NsUvV/1/">http://jsfiddle.net/NsUvV/1/</a></p>
<p>The latter directive can be used in dropdown menus and several other places. It saves us the trouble of adding a controller callback, and can be applied to any DOM element quite easily. It is especially useful within <code class="prettyprint">ng-repeat</code> to easily set the value to a property of a repeated element.</p>
<p>You could also alter it to have an <code class="prettyprint">ng-model</code> on each repeated element, removing the need to use <code class="prettyprint">ng-model</code> on the parent.</p>
<p>And that’s it, really. I just wanted to show how a lot of times simple solutions are all we need. You can go grab Bootstrap, Foundation, or any custom CSS, and easily build a dropdown menu or button group, then apply a few attributes to have a fully functional control.</p>
<p>The implementations above are not optimal and are intended for easy consumption. By utilizing <code class="prettyprint">$parse</code> and making assumptions that the value we are assigning won’t change, we can save a few watch expressions. For the radioValue directive you could refactor away the watching of the model value as well with a little work. These micro-optimizations are nice, but if your web application gets to a point where they are necessary, you probably have too much going on. I like to keep the code clean and readable whenever possible (even at the cost of a bit of performance).</p>
<p>For an optimized and more advanced implementation I recommend taking a look at some of the directives in <a href="https://mgcrea.github.io/angular-strap/">AngularStrap</a>. Here is the source for their button directives.</p>
<p><a href="https://github.com/mgcrea/angular-strap/blob/master/src/button/button.js">https://github.com/mgcrea/angular-strap/blob/master/src/button/button.js</a></p>
<p>Where <code class="prettyprint">bsRadioGroup</code> and <code class="prettyprint">bsRadio</code> would be the radio buttons.</p>
tag:adamkrasny.svbtle.com,2014:Post/getting-started-with-gulp2014-04-12T12:13:49-07:002014-04-12T12:13:49-07:00Getting started with Gulp<p>This is the first in a short series about setting up a sane gulpfile that works for development and production.</p>
<p>Having recently switched from Grunt, I find Gulp to be easier to use and maintain, and I want to share what I’ve learned so far.</p>
<h1 id="initial-setup_1">Initial setup <a class="head_anchor" href="#initial-setup_1">#</a>
</h1>
<p>This guide assumes you already have <a href="http://nodejs.org/">nodejs</a> installed. There should also be a ‘package.json’ in your root application directory, which can be created using <code class="prettyprint">npm init</code>. From there, gulp should be installed globally using <code class="prettyprint">npm install -g gulp</code> and inside of our project dependencies using <code class="prettyprint">npm install --save-dev gulp</code>.</p>
<p>Our first gulpfile will be simple and I will use it to introduce several important plugins.</p>
<h1 id="plugins_1">Plugins <a class="head_anchor" href="#plugins_1">#</a>
</h1>
<p>Install the following gulp plugins using npm <code class="prettyprint">npm install --save-dev <plugin></code></p>
<ul>
<li>
<a href="https://github.com/sindresorhus/gulp-changed">gulp-changed</a> - Run tasks on changed files only.</li>
<li>
<a href="https://github.com/peter-vilja/gulp-clean">gulp-clean</a> - Clean up build artifacts.</li>
<li>
<a href="https://github.com/avevlad/gulp-connect">gulp-connect</a> - Development http server with live reload.</li>
<li>
<a href="https://github.com/jackfranklin/gulp-load-plugins">gulp-load-plugins</a> - Easily load all gulp plugins.</li>
<li>
<a href="https://github.com/stevelacy/gulp-open">gulp-open</a> - Open browser automatically.</li>
<li>
<a href="https://github.com/floatdrop/gulp-plumber">gulp-plumber</a> - Monkey patch to fix stream piping being stopped by errors. Useful for development.</li>
<li>
<a href="https://github.com/OverZealous/run-sequence">run-sequence</a> - As of today, this functionality still doesn’t seem to be implemented in gulp. Check out <a href="https://github.com/orchestrator/orchestrator/issues/21">https://github.com/orchestrator/orchestrator/issues/21</a> for more information.</li>
<li>
<a href="http://lodash.com/">lodash</a> - Some utility functions. Also an awesome library.</li>
</ul>
<h1 id="file-structure_1">File structure <a class="head_anchor" href="#file-structure_1">#</a>
</h1>
<p>There is an assumption about file structure. My app structure is diagramed below, adjust your gulpfile accordingly.</p>
<ul>
<li>app/
<ul>
<li>views/</li>
<li>scripts/</li>
<li>styles/</li>
<li>images/</li>
<li>index.html</li>
</ul>
</li>
<li>build/</li>
<li>gulpfile.js</li>
<li>package.json</li>
</ul>
<h1 id="gulpfile_1">Gulpfile <a class="head_anchor" href="#gulpfile_1">#</a>
</h1>
<pre><code class="prettyprint">var gulp = require('gulp'),
lp = require('gulp-load-plugins')(), // automatically load our plugins
_ = require('lodash');
</code></pre>
<p>Start by requiring the plugins and modules we need. gulp-load-plugins will load plugins and return an object that contains them. For example, gulp-changed will be assigned to <code class="prettyprint">lp.changed</code>, the ‘gulp-’ prefix is removed automatically.</p>
<h3 id="utility-functions_3">Utility functions <a class="head_anchor" href="#utility-functions_3">#</a>
</h3>
<pre><code class="prettyprint">function join(p1, p2) {
if(_.isArray(p2)) {
return _.map(p2, _.partial(join, p1));
}
return path.join(p1, p2 || '');
}
var appPath = _.partial(join, 'app');
var buildPath = _.partial(join, 'build');
</code></pre>
<p>I like to write some helper functions for easy path creation. Take advantage of the path module in node, along with lodash’s ability to partially apply functions. join is now a function that takes a path, p1, and can join it with either an array of paths (in which case it will be mapped to each one) or a single path.</p>
<p><code class="prettyprint">appPath()</code> and <code class="prettyprint">buildPath()</code> can be used to easily set up configuration settings. The views, for example, would be located at <code class="prettyprint">appPath('views')</code> which evaluates to ‘app/views’.</p>
<h3 id="configuration_3">Configuration <a class="head_anchor" href="#configuration_3">#</a>
</h3>
<pre><code class="prettyprint">var config = {
httpPort: '9000',
// views
srcViews: appPath('views/**/*.html'),
destViews: buildPath('views/'),
srcIndex: appPath('index.html'), // this will be more useful in the future
// styles
srcStyles: appPath('styles/**/*.css'),
destStyles: buildPath('styles'),
// scripts
srcScripts: appPath(['scripts/*.js', 'scripts/*/*.js', 'scripts/**/*.js']) // There is reason to this madness, will explain.
destScripts: buildPath('scripts'),
// images
srcImages: appPath('images/**/*'), // supply extensions if you desire
destImages: buildPath('images'),
};
</code></pre>
<p>An object to hold all build configuration. This is pretty straightforward, but we want to define all inputs and outputs so they can be changed from one place.</p>
<p>You may notice srcScripts seems unnecessarily complex. This is just to process files in a specific order. While it doesn’t matter now, this will be useful in the future. Scripts in ‘app/scripts’ first, all subdirectories in ‘app/scripts’, and then the remaining directories recursively.</p>
<h3 id="build-tasks_3">Build tasks <a class="head_anchor" href="#build-tasks_3">#</a>
</h3>
<pre><code class="prettyprint">gulp.task('styles', function () {
return gulp.src(config.srcStyles)
.pipe(lp.plumber())
.pipe(lp.changed(config.destStyles))
.pipe(gulp.dest(config.destStyles))
.pipe(lp.connect.reload());
});
gulp.task('scripts', function () {
return gulp.src(config.srcScripts)
.pipe(lp.plumber())
.pipe(lp.changed(config.destScripts))
.pipe(gulp.dest(config.destScripts))
.pipe(lp.connect.reload());
});
gulp.task('images', function () {
return gulp.src(config.srcImages)
.pipe(lp.plumber())
.pipe(lp.changed(config.destImages))
.pipe(gulp.dest(config.destImages))
.pipe(lp.connect.reload());
});
gulp.task('views', function () {
return gulp.src(config.srcViews)
.pipe(lp.plumber())
.pipe(lp.changed(config.destViews))
.pipe(gulp.dest(config.destViews))
.pipe(lp.connect.reload());
});
gulp.task('index', ['styles', 'scripts'], function () {
return gulp.src(config.srcIndex)
.pipe(lp.plumber())
.pipe(gulp.dest(buildPath()))
.pipe(lp.connect.reload());
});
</code></pre>
<p>All of our basic build tasks come next. The second argument when defining a task can be an array of dependencies. Here, the ‘index’ task depends on ‘styles’ and ‘scripts’. These two tasks will be executed concurrently before the main task, ‘index’, gets run. This comes in handy with more complex gulpfiles.</p>
<p>A few interesting plugins are being used here.<br>
<a href="https://github.com/floatdrop/gulp-plumber">gulp-plumber</a>, used as <code class="prettyprint">lp.plumber()</code>, prevents our tasks from stopping when an error occurs. Without this gulp would die if an error occurred in one of the tasks invoked by a watch. Some tasks, such as Sass compilation, simply need to be rerun and aren’t fatal. This eases the development process by preventing interruptions.</p>
<p>The live-reload feature of <a href="https://github.com/avevlad/gulp-connect">gulp-connect</a>. You can pipe files to <code class="prettyprint">lp.connect.reload()</code> and trigger gulp-connect to send a live-reload message to the browser. This message will only contain the piped files.</p>
<p><a href="https://github.com/sindresorhus/gulp-changed">gulp-changed</a>, will compare piped files to the specified output path, and filter out all files that haven’t changed. It optimizes the build process in development by not rebuilding files that have remained the same.</p>
<p><code class="prettyprint">gulp.dest()</code> is built into gulp and simply writes the piped files to disk.</p>
<h3 id="cleanup_3">Cleanup <a class="head_anchor" href="#cleanup_3">#</a>
</h3>
<pre><code class="prettyprint">gulp.task('clean', function () {
return gulp.src(buildPath(), {read: false})
.pipe(lp.clean())
});
</code></pre>
<p><a href="https://github.com/peter-vilja/gulp-clean">gulp-clean</a> will delete our ‘build/’ directory. By passing {read: false} to <code class="prettyprint">gulp.src()</code>, we tell gulp that we don’t want to read the content of the files. File names are enough to delete a file.</p>
<h3 id="watching-for-changes_3">Watching for changes <a class="head_anchor" href="#watching-for-changes_3">#</a>
</h3>
<pre><code class="prettyprint">gulp.task('watch', function () {
gulp.watch(config.srcStyles, ['styles']);
gulp.watch(config.srcViews, ['views']);
gulp.watch(config.srcImages, ['images']);
gulp.watch(config.srcScripts, ['scripts']);
gulp.watch(config.srcIndex, ['index']);
});
</code></pre>
<p>watch is built into gulp. It will monitor files for changes, and execute one or more tasks. Our tasks watches all project files and runs the rebuild tasks when they are altered.</p>
<h3 id="building_3">Building <a class="head_anchor" href="#building_3">#</a>
</h3>
<pre><code class="prettyprint">gulp.task('build', ['clean'], function (cb) {
runSequence(['index', 'images', 'views'], cb);
});
</code></pre>
<p>build is a collection of tasks. First it will run ‘clean’, then it will run ‘index’, ‘images’, and ‘views’ concurrently. This builds everything we need to have a working version of the application in ‘build/’.</p>
<h3 id="starting-a-server_3">Starting a server <a class="head_anchor" href="#starting-a-server_3">#</a>
</h3>
<pre><code class="prettyprint">gulp.task('server', function () {
lp.connect.server({
root: buildPath(),
port: config.httpPort,
livereload: true
});
});
</code></pre>
<p>server will start up the <a href="https://github.com/torifat/gulp-connect-multi">gulp-connect</a> http server and use the ‘build/’ directory to serve files.</p>
<h3 id="wrapping-it-all-up_3">Wrapping it all up <a class="head_anchor" href="#wrapping-it-all-up_3">#</a>
</h3>
<pre><code class="prettyprint">gulp.task('default', ['build'], function (cb) {
runSequence('server', 'watch', cb);
});
</code></pre>
<p>Finally, the ‘default’ task will build and start a server automatically. It can be run by simply typing <code class="prettyprint">gulp</code>.</p>
<p><code class="prettyprint">run-sequence()</code> let’s us ensure that ‘server’ and ‘watch’ are executed sequentially. The key difference from the first time we saw it is passing an array of strings, as opposed to multiple string parameters. While not currently possible in Gulp, this feature seems to be on the roadmap as seen here <a href="https://github.com/orchestrator/orchestrator/issues/21">https://github.com/orchestrator/orchestrator/issues/21</a>.</p>
<p>All tasks can be executed independently using <code class="prettyprint">gulp <taskname></code>.</p>
<p>That should be enough to get you going. The final result should look something like this.</p>
<p><a href="https://gist.github.com/voxtex/11239483">https://gist.github.com/voxtex/11239483</a></p>
<p>The following comments are inevitable, so I will respond before they come up.</p>
<blockquote class="short">
<p>There’s no point to copying the files, they aren’t modified.</p>
</blockquote>
<p>Correct. It serves no purpose right now, but eventually we will be compiling from Sass and Slim, and performing minification and concatenation. We need to ouput the processed files to some isolated directory.</p>
<blockquote class="short">
<p>There’s no point in using <code class="prettyprint">runSequence()</code> for the build task, as those items are concurrent anyway.</p>
</blockquote>
<p>Also correct. They could simply be defined as dependencies on the task. It was more to illustrate usage of <code class="prettyprint">runSequence()</code>, and will be important later on.</p>
<p>In future posts, I will work on building out the tasks to include typical web development functionality. Sass, Slim, JSHint, and minification will be included along with a bit more.</p>
<p>If you have any suggestions or improvements be sure to comment and let me know.</p>
tag:adamkrasny.svbtle.com,2014:Post/angular-and-slim2013-12-10T18:03:08-08:002013-12-10T18:03:08-08:00Angular and Slim<p>Another layer of abstraction? Why not. In comes Slim, a lightweight<br>
templating engine.</p>
<p><a href="http://slim-lang.com/">http://slim-lang.com/</a></p>
<p>Slim saves you a bit of hassle when you’re writing HTML. IDs and classes<br>
are much easier to identify and assign, attributes are defined<br>
identically to HTML, no more closing tags, and a lot of miscellaneous<br>
utility.</p>
<pre><code class="prettyprint">#item-ctn
.list-item ng-repeat='i in items'
h1() {{i.name}}
span.timestamp() {{i.timestamp}}
</code></pre>
<p>vs </p>
<pre><code class="prettyprint"><div id="item-ctn">
<div class="list-item" ng-repeat="i in items">
<h1>{{i.name}}</h1>
<span class="timestamp">{{i.timestamp}}</span>
</div>
</div>
</code></pre>
<p>If you use grunt for your build workflow this task will come in handy.</p>
<p><a href="https://github.com/matsumos/grunt-slim">https://github.com/matsumos/grunt-slim</a></p>
tag:adamkrasny.svbtle.com,2014:Post/ngbindhtml-and-showdown-to-render-markdown2013-10-25T06:01:43-07:002013-10-25T06:01:43-07:00ngBindHtml and Showdown to Render Markdown<p>An easy way to store formatted text content without having to worry about storing HTML is by using Markdown. Markdown allows you to add headers, links, code blocks, and all other necessary formatting to a string without using any kind of special characters.</p>
<p><a href="https://en.wikipedia.org/wiki/Markdown">Markdown</a></p>
<p>This kind of content is easily stored in a database as a string. Retrieving it is a breeze as well. So what’s left? Rendering it on the client.</p>
<p><a href="https://github.com/coreyti/showdown">Showdown</a></p>
<p>Showdown is a Markdown parser (is that what it’s called?). It can take a<br>
Markdown string and process it into an HTML string. We can assign the<br>
value on our controller since we need to mark it as trusted first.</p>
<pre><code class="prettyprint">$scope.markdownHtml = $sce.trustAsHtml(new Showdown.converter().makeHtml(md);
</code></pre>
<p>A few important points in this code sample.</p>
<pre><code class="prettyprint">new Showdown.converter().makeHtml() // This will take your Markdown string and return an HTML string.
$sce // A service that provides Strict Contextual Escaping.
</code></pre>
<p>Read more about it in the API.</p>
<p><a href="http://docs.angularjs.org/api/ng.%24sce">$sce</a></p>
<p>We need to utilize $sce to let Angular know that the HTML string we are binding to the view is safe. By calling <code class="prettyprint">trustAsHtml</code> we are saying that we know the string is sanitized and it is safe to render.</p>
<p>Now we can easily bind to the view</p>
<pre><code class="prettyprint">div ng-bind-html='markdownHtml'
</code></pre>
<p>markdownHtml is the string value on the scope.</p>
tag:adamkrasny.svbtle.com,2014:Post/debugging-angularjs2013-10-12T16:00:36-07:002013-10-12T16:00:36-07:00Debugging AngularJS<p>Knowing how to debug your code is just as important as writing it.</p>
<p>The most obvious way to debug code is to use <code class="prettyprint">debugger</code> statements in your JavaScript or just breakpoints through Chrome developer tools (or your favorite browser). This works great for fixing code that is executed in a controller, filter, or directive. The bigger problem is view logic that may not be in a controller or simply debugging why certain things aren’t working properly on the view.</p>
<p>One neat trick is to make use of <code class="prettyprint">angular.element</code>. Check out the docs</p>
<p><a href="http://docs.angularjs.org/api/angular.element">Angular Element</a></p>
<pre><code class="prettyprint">angular.element()
</code></pre>
<p>An alias for jQuery, if it is available, otherwise it will use an angular specific jQuery lite implementation. Refer to the documentation for specific DOM functions available through jqLite because they can differ from jQuery quite a bit.</p>
<p>More importantly, check out the extended functions angular provides:</p>
<pre><code class="prettyprint">controller(name)
</code></pre>
<p>Will retrieve the controller being used on this element. If no name is provided, it will be the controller specified by ngController, otherwise you can also retrieve a directive specific controller, such as ngModel.</p>
<pre><code class="prettyprint">scope()
</code></pre>
<p>Retrieve the scope of the current element.</p>
<pre><code class="prettyprint">inheritedData() || injector()
</code></pre>
<p>Are available as well. I don’t find myself using them often, but they<br>
can be useful.</p>
<p>Let’s say you wanted to find the scope of an element with id ‘action-container’. Type something like this into the console.</p>
<pre><code class="prettyprint">angular.element('#action-container').scope();
</code></pre>
<p>All of this stuff is great to know, but really I would recommend just downloading this Chrome extension</p>
<p><a href="https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en">AngularJS Batarang</a></p>
<p>If you open up the developer tools you will have an extra AngularJS tab. Explore the scope or view dependencies. You can even check performance!</p>
<p>Better yet, go to the standard elements tab. Click on any DOM element that is visible in the tree. On the right-hand side you see Computed Styles, CSS Rules, Breakpoints, etc. If you scroll all the way down you have an extra category ‘AngularJS Properties’. This will show you all properties on the scope of the selected element.</p>
tag:adamkrasny.svbtle.com,2014:Post/event-where-does-it-come-from2013-09-29T21:58:28-07:002013-09-29T21:58:28-07:00$event, where does it come from?<p>ngClick, ngMousedown, ngMouseup, and every directive event handler in Angular provide the $event parameter in callbacks. I will show you how to do this with your own directives.</p>
<p>Angular provides an extremely useful service known as $parse. Take a look at the documentation here:</p>
<p><a href="http://docs.angularjs.org/api/ng.%24parse">ngParse</a></p>
<p>So it looks like we can take any Angular expression, convert it to a function, and invoke it in the context of a specific scope and using locals we define. Perfect. Let’s see how we can utilize this when creating a directive for drag and drop.</p>
<pre><code class="prettyprint">app.directive('drag', ['$parse', function($parse) {
return function(scope, elem, attrs) {
var cb = $parse(attrs.drag);
elem.on('dragstart', function(e) {
scope.$apply(function() { cb(scope, { $event: e }); });
});
}
}]);
</code></pre>
<p>Couple of things to note. I protected against minification by using the array syntax to import the $parse service into my directive. This code is integrating with jQuery (notice elem.on).</p>
<p>Otherwise this code is really straightforward. We use $parse to parse the drag attribute on the element. In our case the HTML might look something like this:</p>
<pre><code class="prettyprint"><div drag='onDrag($event)'>Drag Me!</div>
</code></pre>
<p>Since the drag attribute is a function the result of the $parse call will be a function that can be invoked with a scope and optional locals. In our case we are invoking it with the scope of the directive and we are then supplying a custom local which is the event arguments from the event invocation.</p>
<p>Finally, we probably want to wrap the callback in a scope.$apply. While I won’t get into this too much it will essentially run the code within an Angular digest cycle which allows Angular to do it’s thing (model watches, etc.)</p>
<p>So our event handler would look like this</p>
<pre><code class="prettyprint">$scope.onDrag = function(e) {
// Do something here!
};
</code></pre>
<p>And you’re done!</p>
tag:adamkrasny.svbtle.com,2014:Post/isolate-scope-helpers2013-09-10T12:52:15-07:002013-09-10T12:52:15-07:00Isolate Scope Helpers<p><em>Author’s note - This has changed in Angular 1.2. Directives with isolated scopes will only share this isolated scope with other directives that explicitly request it. It will no longer impact regular directives.</em></p>
<p>Isolate scope is a concept which can be really useful. If a directive ever needs to create or manipulate it’s own variables that it will use in a template, you want it to have an isolated scope. Also the ‘@’, ‘&’, and ‘=’ shortcuts seem like they could be really easy shortcuts to reading attributes into a directive. Knowing all of this, I still find myself rarely using them and I’ll tell you why.</p>
<p>Anybody developing with AngularJS needs to be familiar with scope prototypical inheritance. Read about it <a href="https://github.com/angular/angular.js/wiki/Understanding-Scopes">here</a>. There is one key point I would like to highlight:</p>
<p>scope: { … } - the directive creates a new isolate/isolated scope. It does not prototypically inherit. This is usually your best choice when creating reusable components, since the directive cannot accidentally read or modify the parent scope.</p>
<p>Isolated scopes inside of directives do NOT prototypically inherit from parent scopes. Keep in mind this is only when defining a scope using an object. Using scope: true will still give you an isolated scope with inheritance. So this case specifically targets situations where you might use ‘@’, ‘&’, or ‘=’.</p>
<p>Why is this important? Let’s say we’re creating a tooltip directive that wants to grab the contents of its own interpolated attribute to display inside of the tooltip. Ignore which tooltip library we might use and just assume it’s a simple method call. This kind of directive might be defined like so:</p>
<pre><code class="prettyprint">app.directive('tooltip', function() {
return {
scope: {
tooltip: '@'
},
link: function(scope, elem, attrs) {
elem.tooltip(scope.tooltip);
}
}
});
</code></pre>
<p>html</p>
<pre><code class="prettyprint"><input type='text' tooltip='{{property}}'>
</code></pre>
<p>Our isolated scope will have the value of the interpolated attribute, so the tooltip will display the value of property. Looks good right? Well some Angular guys will point out the obvious. We are passing the string value into the tooltip, so it will never update. I should be using an HTML template here with transclusion so the value stays updated, but that’s outside the scope of this post.</p>
<p>The real issue comes in when you suddenly want to use an ng-model on this input element.</p>
<pre><code class="prettyprint"><input type='text' tooltip='{{property}}' ng-model='model'>
</code></pre>
<p>If model was defined on the same scope as property, this would no longer work. Why? Because NgModel is now binding through the isolated scope and it is expecting model to be defined on it. All directives on the same DOM element will share an isolate scope if one is defined on any directive applied. To fix this you would do</p>
<pre><code class="prettyprint"><input type='text' tooltip='{{property}}' ng-model='$parent.model'>
</code></pre>
<p>But this is already turning bad. Why should my directive affect other directives? If somebody wanted to use my directive they would have to be aware of this potential issue. It is very unfriendly.</p>
<p>Because of this, I’ve leaned towards completely avoiding using the isolate scope shortcuts to retrieve attribute values. Instead, make use of the following:</p>
<pre><code class="prettyprint">scope.$eval() // evaluates the expression on the scope and returns the result
$parse() // built in Angular service which can parse an expression that can later be invoked with any scope and custom locals. also gives access to model setters.
scope.$watch() // watches an expression on the scope for changes, provides a callback with new and old values
attrs.$observe() // watches an attribute which contains an interpolated value, provides a callback with the value
</code></pre>
<p>We can rewrite the directive without isolate scope</p>
<pre><code class="prettyprint">app.directive('tooltip', function() {
return {
link: function(scope, elem, attrs) {
attrs.$observe('tooltip', function(val) {
elem.tooltip(val);
});
}
}
});
</code></pre>
<p>Now our tooltip will update when the interpolated value changes and we no longer need to isolate scope which will inadvertently affect other directives. </p>
<p>So what’s the lesson here? Isolate scope with attribute helpers is useful when building directives that will utilize their own template since they are generally self contained. Outside of this use case, it might be better to avoid using isolate scope.</p>
<p>I will try to get some examples along with my posts to make it easier to understand.</p>
tag:adamkrasny.svbtle.com,2014:Post/protecting-against-minification-archived2013-08-08T17:50:33-07:002013-08-08T17:50:33-07:00Protecting Against Minification<p>AngularJS is an interesting beast. The official documentation can be severely lacking. Trying to find answers or examples on the internet frequently turns into a hassle.</p>
<p>Something that I feel that should be covered is ensuring that your Angular code is protected from minification. When using Rails asset pipeline, for example, your JavaScript will be minified by default. This will actually break Angular code unless you explicitly protect against it. A lot of times you won’t even realize there is an issue until you deploy in production.</p>
<p>Assuming we have our application module defined</p>
<pre><code class="prettyprint">var app = angular.module('application');
</code></pre>
<p>this is how you sometimes find controllers defined in examples</p>
<pre><code class="prettyprint">app.controller('sampleCtrl', function($scope) {
});
</code></pre>
<p>but this will break when minified. AngularJS will internally look at the name of the parameter defined, in this case $scope, to inject the appropriate dependencies. What if the variable name is altered by the minification process?</p>
<p>Explicitly define the order of your dependencies using an array instead</p>
<pre><code class="prettyprint">app.controller('sampleCtrl', ['$scope', function($scope) {
}]);
</code></pre>
<p>Slightly more verbose but I consider this best practice and use it in all of my code. The same syntax can be used when defining directives and factories.</p>