Issue
I know we can achieve conditional binding with ng-repeat through the following:
<tr ng-repeat="viewer in allViewers track by viewer.Id">
<td>
<img width="18" ng-src="{{!viewer.StatusByUser || viewer.StatusByUser != 1 ?
'/images/icons/hide.svg' : '/images/icons/show-18x11.png'}}"
onerror="this.src='/images/icons/hide.svg'" alt="Viewer Status"
title="Click to {{!viewer.StatusByUser || viewer.StatusByUser != 1 ?
'publish' : 'unpublish'}}" ng-click="manageViewerStatus(viewer.StatusByUser)">
</td>
</tr>
But as you can see, this is messy and in reality, I have at least 5 to 6 status to keep track of and change the display image icon accordingly.
In JavaScript, we know that there is a way to pass the current element to a function:
<img src="/images/icon.jpg" onclick="changeAttr(this)" />
But in Angular, I tried the following but not working:
In HTML:
<img data-bind="{{renderStatusImg(this, viewer)}}" width="18" alt="Viewer Status"
title="Click to publish" ng-click="manageViewerStatus(viewer.StatusByUser)">
In controller:
$scope.renderStatusImg = function (img, viewer) {
$(img).attr("src", !viewer.StatusByUser || viewer.StatusByUser != 1 ? '/images/icons/hide.svg' : '/images/icons/show-18x11.png');
// More complex logic can be written here in future to cater for more status.
return viewer.Id;
};
As a result, viewer.Id can be returned and rendered in data-bind attribute, but the src attribute isn't rendered. I have heard of the directive approach but seems like it can only deal with the indexes of the underlying data and not the element itself. Any help will be appreciated, thank you.
Solution
As suggested by @Ruben Helsloot, the question itself may not be a good practice. Apparently, not all technical questions have their own direct good answer, but all goals may have variety of solutions to achieve them for the same result, of which they may include best practices, moderate solutions, or even just a work-around. Therefore, it's good for solution seekers to share also their GOALS as their question alone may not be a recommended good practice.
Now my answer: Using ng-switch for the same goal
After a more extensive research, I found ng-switch is my perfect solution: Cleaner, less code, more extensible and readable, yet more Angular native:
<tr ng-repeat="viewer in allViewers track by viewer.Id" ng-switch on="viewer.StatusByUser">
<td>
<img ng-switch-when="0" src="/images/icons/hide.svg" width="18" alt="Draft" title="Click to publish" ng-click="manageViewerStatus(viewer)">
<img ng-switch-when="1" src="/images/icons/show-18x11.png" width="18" alt="Published" title="Click to unpublish" ng-click="manageViewerStatus(viewer)">
<img ng-switch-default src="/images/icons/hide.svg" width="18" alt="Old version" title="Click to fix" ng-click="manageViewerStatus(viewer)">
</td>
<td>
<!-- More other columns that bound by viewer.StatusByUser can be benefited
from this approach. -->
</td>
</tr>
Take note of the ng-switch-default, it is one of the main factors that led me to choose ng-switch: It can handle null and undefined object property, great for allowing you to offer fallback and upgrade services to your users. Notice also the title and alt attributes, I can properly define them in every conditional tag for ng-switch -- No complex code and logic required. Note that I don't even have to write a single additional JavaScript to handle this. Thanks to ng-switch.
Answered By - Antonio Ooi
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.