Showing posts with label web. Show all posts
Showing posts with label web. Show all posts

Sunday, October 2, 2016

Creating A Fancy CSS Button

I was in a meeting at work the other day where we were discussing our interview process for front-end developers.  We were taking a step back and trying to decide what exactly we were going to look for in our interview process and if we were finding those skills in the developers we were interviewing.  During the process the thought of interviewing for CSS was brought up and we started looking into some possible interview questions and stumbled across this website.
The first one is a simple question, but was really interesting.  People in the room seemed to think it was way too hard and I wasn't 100% sure how I would do it without internet access.  Here is the question:  Using CSS properties alone, recreate this button:

So I decided to take this as a personal challenge and ended up coming pretty close to it by just eyeballing the colors, spacings, etc.  It also took me way less time than I thought it would have and I learned a few things in the process.  Here is the end result:

Breaking it down, I started with the easies things first to get me going.  So I tackled the actual text of the button as my first thing.  To get the text to appear correctly, I knew the font-family needed to be a Sans-Serif, the font weight to be a bit on the bold size, to update the text color to a dark grey instead of black, and finally to just make sure whatever text in the button is uppercase.  Here is the css to do those things:

.button {

  text-transform:uppercase;

  color:#444444;

  font-family:sans-serif;

  font-weight:bold;

  font-size: 14px;

}



The next thing I decided to tackle was the stars.  The solution to this is to use a font-family, svg, or something else with before and after selectors.  If you haven't used them before check out the article about using after and before selectors.  I decided to use font-awesome in my solution because it had a star icon and I could just reference the CDN in my jsfiddle.   If you haven't used font icons before I wrote about it previously here.  I messed with the colors a bit and ended up with some pretty simple before and after selectors.

.button::before{

   font-family: FontAwesome;

   color:#999999;

   content: "\f005";

}




.button::after{

   font-family: FontAwesome;

   color:#999999;

   content: "\f005";

}


So now that the content is correct, the next thing was to take a stab at the background and the the first border.  So I added some padding to get the spacing of the button correct, and then went to work on the background.  I knew you could have gradients in css, but I hadn't used them in a while so I didn't quite remember the syntax.  I found some examples online like this and then created a gradient to the bottom with my 2 shades of gray.  Finally I added a simple boarder and some border radius and we are starting to look pretty good now.

.button{

  margin-left:10px;

  text-transform:uppercase;

  color:#444444;

  font-family:sans-serif;

  font-weight:bold;

  font-size: 14px;

  border-radius: 5px;

  border:.5px solid #aaaaaa;

  background: linear-gradient(180deg, #eeeeee, #aaaaaa);

  padding: 10px;

}


The last thing that was needed also the thing I was least certain about.  I was sure it could be done, cause otherwise why would the ask the question?  So I looked into box-shadow to see how that could be used and found something amazing.  It can be used N number of times!  So I finally had my solution.  I just needed a few different levels of box-shadow.  I needed one really dark layer around the border, followed by the larger light gray area.  Next I added a white gap followed by the final border.  Here is the final css for the .button class.

 
.button{

  margin-left:10px;

  text-transform:uppercase;

  color:#444444;

  font-family:sans-serif;

  font-weight:bold;

  font-size: 14px;

  border-radius: 5px;

  border:.5px solid #aaaaaa;

  background: linear-gradient(180deg, #eeeeee, #aaaaaa);

  box-shadow:  0 0 1px 1px #666666,

            0 0 0 6px #dddddd,

            0 0 0 8px #ffffff,

            0 0 0 10px #888888;

  padding: 10px;

}


Cheers!




Monday, September 21, 2015

Learning ECMA Script 6: Arrow Functions

If you are familiar with a language other than JavaScript, there is a good chance that language already supports something similar to => functions.  In ES6 they are called arrow functions (or FAT arrow functions) and 9 times out of 10 they replace anonymous functions.  There is one major case where they differ, and I will get to that in my last point.




The first way to use an arrow function is the same any way you would use function (param1, param2, ...) { ... }.  Instead of that you would write the following:

   
(param1, param2, ...) => { ... }; 

It is pretty straight forward and it is shown in the example below:

var closureVariable = 'foo';
var test1 = () => {
    var innerVariable = 'bar';
    // look ma!  Closure still works.
    return closureVariable + innerVariable;
};

document.getElementById('test1').innerHTML = 'Test 1: ' + test1();


As you can see, no magic there.  It is simply replacing function (param...) with (param...) =>.  Most places you have anonymous functions are in callbacks and promises.  While it was super weird at first using them I found my code to be easier to read now (especially jasmine unit tests) and rarely write the word function anymore.

Now if you have a function that is one line and returns something, you can make the arrow function one line.  Imagine you were using the lodash function map that will "map" your current array into another one.  You just need to supply the function to transform each object.  Imagine you just wanted a property out of that array like name.  Before you would need something like this:

    
_.map(list, function(item){ return item.name;});


Now you can write this:

    
_.map(list, item => item.name);


item.name is implicitly returned since it is not surrounded with curly braces.



So you might ask, that's fine, but what if I want to return an object?  I need curly braces for that!  The answer is, Yes you do!  So to do this you would wrap your object in parenthesis and the above will still work.

So you would write the following:

    
_.map(list, (item) => ({ id: item.id, name: item.name}));





There one major difference between anonymous functions and arrow functions is how this is defined in the function.  Arrow functions now have Lexical this. 

What does this mean?  The easiest way would be to show you the difference in these two examples:

Suppose I have the following object.
  
var solarSystem = {
        planets: ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto'],
        star: 'Sun'
    };


Now I want to add some function to that object that does something to the array, and references some other property on the object.

    solarSystem.performOperation = function(){
        this.message = '';
        this.planets.forEach(function(p, i) {
            this.message += p + ' is planet number ' + (i + 1) + ' from the ' + this.star + '.  ';
        });
    };


What happens if you run this code? You will get the following:  

solarSystem.message === ''; //true

Why? This is because in the forEach function 'this' is defined as the window object. So the window object will have a message property on it that contains the following:  

window.message = 'undefinedMercury is planet number 1 from the undefined. Venus is planet number 2 from the undefined. Earth is planet number 3 from the undefined. Mars is planet number 4 from the undefined. Jupiter is planet number 5 from the undefined. Saturn is planet number 6 from the undefined. Uranus is planet number 7 from the undefined. Neptune is planet number 8 from the undefined. Pluto is planet number 9 from the undefined. ' 

 
However if you write the same code using arrow functions like in the fiddle below you will get the desired result.


Cheers!

Part 1 - Math & Numbers
Part 2 - New Parameter Features 

Friday, January 2, 2015

Using jQuery Plug-ins With Angular (jScrollPane)

I needed to allow for a particular part of a page I was working on to scroll independently of the page.  Typically you would just use overflow-y: auto and be call it a day.  However the default renderings of these scroll bars stick out like sore thumbs in the middle of a page.



So I quickly googled to see if there were any awesome angular.js directives that allowed you to style scrollbars.  Much like the flyout, confirm dialog, and dropdown, I didn't find much online.  I did find a bunch of posts on jQuery controls that have nice scrolling like jScrollPane.  I figured that instead of creating one from scratch this time, I was more curious on the proper way of integrating jQuery plugins with angular.js.

I found this video that shows an integration with the chosen jQuery plugin, which incidentally was something I was looking at when I decided to create my own drop down, and I decided to watch it.  The video is pretty good, but regardless if you watch it or not I'll show you how to integrate a jQuery plugin with angular.js.

So after viewing that example I figured it would be pretty easy.  It should be just adding the JS files and creating a directive that applies the plugin to the element in the link function.  It pretty much boils down to the following directive.
 
.directive('NAME', function(){
    
    function link(scope, element){
        // you can use the angular.element instead
        $(element).PLUGINFUNCTION();

    }    
    
    return {
        link:link,
        restrict : "A"
    };
});

Just replace the 'NAME' with a proper name for the directive, and 'PLUGINFUNCTION' with the actual function to execute the plugin.  I have it restricted as "A" so you can just add the attribute to whatever element you want it to be on.  So to use the jScrollPane plugin you can just use this.
 
.directive('scrollPane', function(){
    
    function link(scope, element){
        // you can use the angular.element instead
        $(element).jScrollPane();

    }    
    
    return {
        link:link,
        restrict : "A"
    };
});

I tried it out in a fiddle real quick and it worked fine.  However when I tried to use it in my application it wasn't working.  After thinking about it for a bit, and reading some additional  documentation for the jScrollPane, I realized the issue was, like most JS heavy applications, were being driven by data from services, or in my case being asynchronously loaded via websockets.

So now I found the function to reinitialize the plugin, but I needed to figure out how to inform the directive to do it.  I ended up deciding to use a built in angular functionality to do so.  The scope.$broadcast and scope.$on  seemed to be exactly what I was looking for.  Whenever what was driving the content changed it would send a message down scope using $broadcast, and $on would listen for the message.  That made me feel good about the separation of concerns.  Essentially the scrollPane directive could just listen for an event from somewhere up the parent scope and whatever was driving the data or re-sizing of the page could drive the sending of the message.  I ended up just using a generic "refresh" message name for it.  Here is the end result for the directive:

 
.directive('scrollPane', function(){
    function link(scope, element, attr){
        
        var $element = $(element),
            api;
        
        // element.jScrollPane();
        //In real world Angular would replace jQuery
        $element.jScrollPane();
        api = $element.data('jsp');
        
        scope.$on('refresh', function onRefresh(event, args){
            api.reinitialise();
        });
        
    }
    
    return {
        restrict: 'A',
        link: link
    };
});

Here is the end result:


Monday, December 15, 2014

Custom Angular Flyout

While working recently on a project I came across an issue where I had a finite amount of space and a bunch of actions that would be visible or hidden based on its current state.  I put some time into thinking how I could fit everything I needed and I thought that +90% of the time the user won't be performing any actions beyond just viewing the data so I started thinking about how to minify the amount of space my buttons took up.  I first thought about using icons, but unless they are so universal, it is typically better to just go with text.  So I thought about a button that has a popup menu.  I'm not sure if flyout is the technical term for it, but that sounded right to me so that is what I went with.  One of the benefits of this approach was if I needed to add more buttons down the road I know it won't cause any issues.  Likewise I will always know exactly how much real estate it will take up.
You could have infinite benders take up a finite space!

I knew that I wanted my angular directive to have a couple of things.  First I wanted the flyout to be driven by the developer so it can be reused over and over.  This can be easily solved with an ng-transclude directive.  Secondly, I wanted to make sure that it was smart enough to figure out where it was positioned in the window and dynamically display based on its position in the window.

The HTML for the flyout should be pretty straight forward.  An outer container, .flyoutContainer,  for the control, a container for the flyout, .flyout, and a div for the text/button to expand the flyout, .expanderContainer.  The .flyoutContainer has a couple events on it, blur and click, to figure out when to display the .flyout, and a ng-class directive to help with any styles you want to apply as well.  Here is the HTML result:
 
<div class='flyoutContainer' tabindex='0'  ng-click='click();' 
   ng-blur='lostFocus();' ng-class='{"expanded": options.isExpanded}'>
     <div class='expanderContainer' >
       {{options.display || 'Expand'}}
     </div>
     <div class='flyout'  ng-transclude ></div>
</div>

Next is the bare bones CSS to handle what we need.  We want the .flyout to be absolutely positioned, to start off hidden, and to go on top of other elements.  When the .expanded class is applied we will then want to change the visibility so the .flyout and its contents will be displayed.  The .flyoutContainer styles are pretty simple.  Change the positioning to relative so the absolutely positioned .flyout will be relative to it, and remove any outlining (unless you are into that kind of thing).  For the .expanderContainer I just added css to change the pointer to a cursor to make it explicit that it is clickable.  Here is the css:
    
.flyoutContainer{
    outline:none;
    position: relative;
}

.expanderContainer{
    cursor:pointer;
}

.flyout{
    position:absolute;
    top:auto;
    left:auto;
    z-index:1;
    visibility:hidden;
}

.expanded .flyout{
    visibility:visible;
}

Finally we come to the JS code to put it all together.  The easy part of the code is to just set the options.isExpanded appropriately based on the current state and event.  This will drive the CSS above.  The more difficult part of the code is making sure that the positioning of the .flyout is set appropriately based on where it is located in the window.  For this we pass in the $window parameter to the directive to get the window height and width.  We use the $window param instead of the window global element to make life easier for unit testing.  We can then compare those values with the getBoudingClientRect values of the .flyout to determine how much you need to update the top and left properties of it.  Here is the resulting JS:

function link(scope, element){
    scope.lostFocus = function lostFocus(){
        scope.options.isExpanded = false;
        clearFlyoutPosition();
    };

    scope.click = function click(){
        updateFlyoutPosition();
        scope.options.isExpanded = !scope.options.isExpanded;

        if (!scope.options.isExpanded){
            clearFlyoutPosition();
        }
    };
       
    function clearFlyoutPosition(){
        var $flyoutElement = angular.element
            element[0].querySelector('.flyout'));
        $flyoutElement.css('top', 'auto');
        $flyoutElement.css('left', 'auto');
    }

    function updateFlyoutPosition(){
        var flyoutElement = element[0].querySelector('.flyout'),
            $flyoutElement = angular.element(flyoutElement);

        if ($window.innerHeight < 
            flyoutElement.getBoundingClientRect().bottom){
            $flyoutElement.css('top', '-' +
                (flyoutElement.getBoundingClientRect().height ) + "px");
        }
        else{
            // set the top to the flyout container so it starts right at the bottom.
            $flyoutElement.css('top','auto');
        }

        if ($window.innerWidth < 
            flyoutElement.getBoundingClientRect().right){
            $flyoutElement.css('left', "-" +
                (flyoutElement.getBoundingClientRect().right -
              $window.innerWidth + 10) + "px");

        }
        else{
            $flyoutElement.css('left', 'auto');
        }

    }

}


Here is the end result with one flyout in the top left and one in the bottom right!




Monday, December 1, 2014

Create Your Own Angular Confirm Dialog


Modal dialogs have always been kind of iffy to use in regards to UX.  This goes 1000000x for web dialogs.  While most browsers somewhat support showModalDialog, it definitely isn't recommended to use for a lot of reasons.    I do believe that dialogs like other maligned things still have their place if used properly.

Loud Noises!
The type of dialogs I am referring to on the web are typically not traditional dialogs, but a transparent div of height/width of 100%.  You can find these types of dialogs all over the internet for all kinds of various things.  Even as I create this blog post blogger had a custom dialog to insert an image, and a hyperlink.
Blogception
So I wanted to create something that I could reuse and style easily as well as incorporate in my work.  An angular directive seemed like the right approach for this.  I ended up creating a simple confirm dialog that you could set the text for the title, detail, and buttons, as well as the confirm and cancel button callbacks.  

The first thing I started out with was the HTML for the dialog.  It should be pretty straightforward,  one container to take the entire page, one div that is centered in the middle of the page and is the height and width of whatever we desire it to be, the title, the detail, and the buttons.  Here is what that looks like: 
      
    <div class='confirm' ng-hide='!showPrompt'> 
        <div class='confirmContainer'>
            <div class='confirm-title'>{{confirmTitle}}</div> 
            <div class='confirm-detail'>{{detailText}}</div> 
            <div class='confirm-actions'>
                <button class='ok' btn' ng-click='ok()'>{{okText || 'OK'}}</button>
                <button class='cancel btn' ng-click='cancel()'>{{cancelText || 'Cancel'}}</button> 
            </div> 
      </div>
</div>

Next lets add some basic CSS for this dialog to center everything, and set the height/width appropriately.  We want the dialog to take the entire height & width of the page with a transparent background.  To center the container vertically we put the top at 50% and then set a negative margin top to move it back up.  We then put the buttons container to the bottom right of the confirmContainer.   
      
.confirm{
    height:100%;
    width:100%;
    position: fixed;
    top:0;
    opacity: 1;
    left:0;
    background-color: rgba(3, 3, 3, .25);
    z-index: 1000;
}

.confirm .confirmContainer{
    position: relative;
    top:50%;
    width:50%;
    margin: 0 auto;
    height:200px;
    margin-top: -50px;
    background-color: rgba(255, 255, 255, 1);
}

.confirm .confirm-actions{
    position: absolute;
    bottom:10px;
    right:10px;
}

Finally lets get to the directive code.  We are going to use an isolated scope to bind whatever properties we want as well as the 2 functions we want to call.  We will also bind a showDialog property on the scope that will show the dialog when it is set to true.  When we want it to hide we will then set it back to false in our button code.  Pretty easy.  Here is the whole directive:

 
.directive('confirm', function(){
    var template ="<div class="confirm" ng-hide="!showPrompt">
" + 
        "<br />
<div class="confirmContainer">
" + 
            "<br />
<div class="confirm-title">
{{confirmTitle}}</div>
" + 
            "<br />
<div class="confirm-detail">
{{detailText}}</div>
" + 
            "<br />
<div class="confirm-actions">
"+
                "<button btn="" class="ok" ng-click="ok()">{{okText || 'OK'}}</button>"+
                "<button class="cancel btn" ng-click="cancel()">{{cancelText || 'Cancel'}}</button>" + 
            "</div>
" + 
        "</div>
</div>
";
    
    function link(scope){
        scope.cancel = function cancelFunc(){
            scope.showPrompt = false;
            scope.cancelFunction();
        };
        
        scope.ok = function okFunc(){
            scope.showPrompt = false;
            scope.okFunction();
        };
    }
    
    
    return {
        template: template,
        link:link,
        scope:{
            confirmTitle: '=',
            detailText: '=',
            cancelText: '=',
            okText: '=',
            okFunction: '&',
            cancelFunction: '&',
            showPrompt: '='
        },
        restrict : "E"
    };
});

Now the dialogs in action:




Some next steps for this would be to create an even more generic dialog using ng-transclude so you can have your own picture upload dialog.  Likewise, another way I thought of using this confirm dialog was to use this in conjunction with a dialog service that had access to the rootScope.  That way you could have 1 dialog in your root page and have your service open/close that one as necessary.  

Tuesday, November 18, 2014

Custom Dropdown With Angular.

The more I get into front-end development the more I end up disliking standard HTML inputs.  I dislike them for different reasons, but my biggest issue has been the inability to style them how I need them to.  This goes especially double for new HTML 5 elements that you pretty much have to jump through hoops to get any kind of custom styling.  I already took on restyling a checkbox since it doesn't really work well for my fat fingers.  Now I am going to take on the select tag.

What styling a select feels like.
I don't really dislike the select tag.  Overall it is pretty simple and you can style most of it.  However. if you end up deciding to style it with colors of any type, then you will hate it.  You will hate it because you can't change the hover color when it is expanded.  You will hate it because you can't change the arrow/box at the end that indicates it is a drop down.  You will hate it even more because not only can these styles not be modified, but they are different per browser/OS combo.

So after googling a bit, I didn't find anything I completely liked, so I decided I would handle it myself.  I decided that since I would be using it for angular development that I would make it a directive and have it function as a select element, that can be customized.

Here is the end result.






Wednesday, December 18, 2013

Writing Elegant HTML

The other day I was thinking to myself, "Self, I wonder if there are any books on writing elegant HTML and CSS."  I'm sure there are I thought, and spent some time looking on Amazon for a book.  I was hoping for something that would essentially teach me the correct way to do things since I am pretty much self taught in the area of web development and would like to know what I am doing right and what I am doing wrong.  Unfortunately I didn't find a book that was suitable for what I was looking for.  However I did find a site that I found just as good, if not better. The website, Webplatform.org, has a lot of nice tutorials on it, with explanations why to do it that way.

So far I have only gone through the HTML and part of the CSS tutorials, but I have already found plenty of flaws in the HTML I used to write and definitely plan on changing the way I write it to become more semantic of the page I am writing.  By writing html that is more semantic it makes everything clearer to other developers what the element does, and it also helps out those with disabilities that need to use things like screen readers.

Thursday, August 22, 2013

Getting Started With Angular Part 3. Factories, Promises, and Injections. Oh My!

This post will cover a few major topics in Angular including factories, promises, and injection.  In Angular, when you are writing your actual app you will most likely have some kind of service or rest endpoint that you are hitting.  Angular has a lot of features that help you write your code in a cleaner and more maintainable way, or allow you to use your existing services and just leverage the features you want in an Angular app.

When defining a service in Angular, there are two different modules provided for you.  They are the factory module and the service module.  They are fairly similar, but in the end I chose to use the factory module because 99% of the examples on the Angular site are done using it instead of the service module.  For some more info on the differences on these two modules you can check out this SO post.