“Become a beacon of enhancement, and then, when the night is gray, all of the boats will move towards you, bringing their bountiful riches.”
— James Altucher
After I posted the SNH Data Table widget collection out on Share, there were a couple of things that I felt were missing in the version that I put out there. One of those was the ability to click on an aggregate column and pull up a list of the records represented by that value. I took care of that one here, but after having second thoughts, the version that I ended up with is not quite like the one described in that installment of the series. Still, after a litter refactoring, I got it working in a way that finally seemed to be acceptable. But there is still one more thing that I would like to add before I release another version of the collection: the ability to control the presence of a button or icon on the row based on some condition.
Right now, if you configure a button or icon, that button or icon appears on every row of the table. That’s a nice feature that the stock Data Table widget does not include, but it would be even nicer if you could control whether or not the button appeared based on some condition. My thought was that I could add yet one more property to the button/icon configuration object called condition that could be used to control the presence of the action item on the row. I wasn’t exactly sure how to make that happen, but as usual, I thought that I would tackle the easiest portion first, which would be to modify the Content Selector Configurator widget to include that additional property. We just went through that exercise when adding the action property to the aggregate column configuration object (which was later replaced with the hint and page_id properties during refactoring), so the exercise is virtually the same.
As we did with the new aggregate column configuration property, we can start with the main widget and add the following to the list of column headings for the buttons and icons section of the table specification:
<th style="text-align: center;">${Condition}</th>
And then in the repeating rows of that table, we can insert this line:
<td data-th="${Condition}">{{btn.condition}}<
On the client side, we can add the following line to the new record section of the editButton() function:
shared.condition = button.condition;
… and this line to the section that saves the edits in that same function:
button.condition = shared.condition || '';
Finally, on the server side, in the Save() function that rebuilds the script, let’s add these lines in the button/icon specification section:
script += "',\n                condition: '";
script += thisButton.condition;
That will handle things in most cases, but since this particular property is a Javascript expression, we need to account for the fact that the value might contain single quotes, and surrounding a value containing single quotes with single quotes will result in a syntax error in our Script Include. We should at least check for that, and if single quotes are present in the value, we should escape them. Instead of the script fragment above, which has been working for us in all other cases, let’s expand that a little bit to accommodate our concerns to something like this:
script += "',\n condition: '";
if (thisButton.condition) {
var condition = thisButton.condition;
if (condition.indexOf("'") != -1) {
condition = condition.replace(/'/g, "\\'");
}
script += condition;
}
That takes care of the main widget, but we also need to add a new input field to the pop-up editor before this will actually work, so we need to add this line to the HTML of the Button/Icon Editor widget:
<snh-form-field snh-model="c.widget.options.shared.condition" snh-name="condition"/>
That updates the editor to now include a new button/icon specification property called condition. Of course, that doesn’t actually add any functionality to the Data Table widgets just yet, but at least now we can add a value to that property through the editor, which is a start. Now let’s take a look at the actual SNH Data Table widget and see what we need to do in order to leverage that new property.
Once again, the easiest place to start is with the HTML. Here is the current section of the HTML that deals with buttons and icons:
<td ng-repeat="button in data.btnarray" role="cell" class="text-nowrap center" ng-class="{selected: item.selected}" tabindex="0">
<a ng-if="!button.icon" href="javascript:void(0)" role="button" class="btn-ref btn btn-{{button.color || 'default'}}" ng-click="buttonClick(button.name, item)" title="{{button.hint}}" data-original-title="{{button.hint}}">{{button.label}}</a>
<a ng-if="button.icon" href="javascript:void(0)" role="button" class="btn-ref btn btn-{{button.color || 'default'}}" ng-click="buttonClick(button.name, item)" title="{{button.hint}}" data-original-title="{{button.hint}}">
<span class="icon icon-{{button.icon}}" aria-hidden="true"></span>
<span class="sr-only">{{button.hint}}</span>
</a>
</td>
In the current version, there are two mutually exclusive anchor tags controlled by ng-if attributes that look to see whether or not an icon image was specified. We should be able to logically and our new condition to the existing conditions without disturbing the rest of the existing structure. The easiest way to do that at this point would simply be to call a function that dealt with the condition and have it return true or false based on the contents of our new condition property. We will have to build that function, but for now, we can just assume that it exists and modify the above to now look like this:
<td ng-repeat="button in data.btnarray" role="cell" class="text-nowrap center" ng-class="{selected: item.selected}" tabindex="0">
<a ng-if="!button.icon && buttonCondition(button.condition, item)" href="javascript:void(0)" role="button" class="btn-ref btn btn-{{button.color || 'default'}}" ng-click="buttonClick(button.name, item)" title="{{button.hint}}" data-original-title="{{button.hint}}">{{button.label}}</a>
<a ng-if="button.icon && buttonCondition(button.condition, item)" href="javascript:void(0)" role="button" class="btn-ref btn btn-{{button.color || 'default'}}" ng-click="buttonClick(button.name, item)" title="{{button.hint}}" data-original-title="{{button.hint}}">
<span class="icon icon-{{button.icon}}" aria-hidden="true"></span>
<span class="sr-only">{{button.hint}}</span>
</a>
</td>
That should take care of the HTML. Now we need to come up with a function that will do what we want to do, which is to return true if we want the button/icon to appear and false if we do not. We can start out with something like this:
$scope.buttonCondition = function(expression, item) {
var response = true;
if (expression) {
// check to see if the condition is true or false
}
return response;
};
This defaults the response to true, and if there is no condition specified, then the response will be true. If there is a condition, then we need to see if that condition is true for this item. Basically, we want to run the code that is stored in the property value. For that, we can use $scope.$eval. This AngularJS function will run the expression and return the result, which will then become our response. That will make our function look like this:
$scope.buttonCondition = function(expression, item) {
var response = true;
if (expression) {
response = $scope.$eval(expression, this);
}
return response;
};
And that should be that! Now all we need to do is test all of this out, plus do a whole lot of regression testing for all of the refactoring, and then we can finally put out a new Update Set. That is definitely quite a bit of work in an of itself, so let’s save all of that for a future installment.