Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

All elements of the array (except the last) are the names of services to inject into the directive function (the last element of the array). In this case we are injecting references to the Panel Service and the Key Service.

 

 

 

Warning

WIP

 

sample.css

Our function returns an object to allow Angular to configure our directive:

Code Block
languagejs
return {
    restrict: 'E', 
    link: function (scope, element, attrs) {
        ...
    }    
};

The restrict property is set to "E" to tell angular that this directive is an element.

The link function is invoked when Angular parses the HTML document and finds the <ov-sample-item-details-panel> element. Our function sets up the "floating panel" behaviors as follows:

Code Block
languagejs
var panel = ps.createPanel(pName, {
    width: 200,
    margin: 20,
    hideMargin: 0
});
panel.hide();
scope.hidePanel = function () { panel.hide(); };

First, use the panel service to create the panel, and start with the panel hidden. Also store a hidePanel() function on our scope which we can invoke later.

Next we define a callback to hide the panel if it is visible; to be bound to the ESC keystroke:

Code Block
languagejs
function closePanel() {
    if (panel.isVisible()) {
        $scope.selId = null;
        panel.hide();
        return true;
    }
    return false;
} 

Note that escape key handlers should return true if they "consume" the event, or false otherwise.

Now we use the key service to bind our callback to the ESC key, and also provide hints for the Quick Help panel:

Code Block
languagejs
// create key bindings to handle panel
ks.keyBindings({
    esc: [closePanel, 'Close the details panel'],
    _helpFormat: ['esc']
});
ks.gestureNotes([
    ['click', 'Select a row to show item details']
]); 
Info

See the Key Service for more details on binding keys / configuring quick help.

 

Next, we set up "watch" function to be triggered any time the panelDetails property on our scope is changed to be a non-empty object. When invoked, the function clears, then populates, the panel with data and makes it visible.

Code Block
languagejs
// update the panel's contents when the data is changed
scope.$watch('panelDetails', function () {
    if (!fs.isEmptyObject(scope.panelDetails)) {
        panel.empty();
        populatePanel(panel);
        panel.show();
    }
}); 

Now would be a good time to revisit those helper functions that we glossed over earlier. First, populatePanel()...

Code Block
languagejs
function populatePanel(panel) {
    var title = panel.append('h3'),
        tbody = panel.append('table').append('tbody');

    title.text('Item Details');

    propOrder.forEach(function (prop, i) {
        addProp(tbody, i, $scope.panelDetails[prop]);
    });

    panel.append('hr');
    panel.append('h4').text('Comments');
    panel.append('p').text($scope.panelDetails.comment);
}

This function is given a reference to the panel instance. It uses that API to build up the panel contents from the data stored in the panelDetails property of our scope.

Recall, propOrder was defined as an array (at the top of our script) listing the order in which the properties of the data should be added to the panel.

The addProp() function adds a property line item to the panel:

Code Block
languagejs
function addProp(tbody, index, value) {
    var tr = tbody.append('tr');

    function addCell(cls, txt) {
        tr.append('td').attr('class', cls).html(txt);
    }
    addCell('label', friendlyProps[index] + ' :');
    addCell('value', value);
} 

Recall, friendlyProps was defined as an array listing the "human readable" labels for each of the properties.

 

And finally... add a cleanup function for when our scope is destroyed (user navigates away from our view):

Code Block
languagejs
 // cleanup on destroyed scope
scope.$on('$destroy', function () {
    ks.unbindKeys();
    ps.destroyPanel(pName);
});

Unbind our ESC key handler and gesture notes and destroy the floating panel instance.

sample.css

The last file in our client-side trio is the stylesheet for the sample view.

Code Block
languagecss
linenumberstrue
collapsetrue
/* css for sample app view */

#ov-sample h2 {
    display: inline-block;
}

/* Panel Styling */
#ov-sample-item-details-panel.floatpanel {
    position: absolute;
    top: 115px;
}

.light #ov-sample-item-details-panel.floatpanel {
    background-color: rgb(229, 234, 237);
}
.dark #ov-sample-item-details-panel.floatpanel {
    background-color: #3A4042;
}

#ov-sample-item-details-panel h3 {
    margin: 0;
    font-size: large;
}

#ov-sample-item-details-panel h4 {
    margin: 0;
}

#ov-sample-item-details-panel td {
    padding: 5px;
}
#ov-sample-item-details-panel td.label {
    font-style: italic;
    opacity: 0.8;
} 

It should be fairly self-explanatory. However, note the use of the .light and .dark classesStylesheet for the sample view. Again, a number of naming conventions are in use here: