1

My static html table has a row click event which hightlights a div.

The static table is working fine, but my ng-repeat table has some issues. I can now highlight my div with a red border, but how do I remove the border when something else is clicked ?

Here's the static table example :

<script type="text/javascript">
    
    $('.image-clicked').click(function () {
        debugger;
        $(this).css("border", "2px solid red");
    });

    $('.clickable_row td div').click(function (e) {
        // clear all borders first, highlight  clicked image
        var imageclicked = $(this).data('url');
        $('.propertyTable td div').css("border", "none");
        
        $(this).css("border", "2px solid red");                        
    });
</script>
<table id="gadgets" class="propertyTable clickable_row">

        <tr>
            <th>Type</th>
        </tr>
        <tr>
            <td data-url="chart_treelist">
                <div><img data-draggable id="chart_treelist" src="images2/table.png" title="Tree Grid" alt="Hierarchy Grid" width="64" height="64">Grid</div>
            </td>   
            <td data-url="{chart_pivot}">
                <div><img data-draggable id="chart_pivot" src="images2/pivottable.png" title="Pivot Table"   alt="Pivot Table" width="64" height="64">Pivot</div>
            </td> 
        </tr>
        <tr>
            <td>
                <div><img data-draggable id="chart_bar" src="images2/bar.png" title="Bar" width="64" height="64">Bar</div>
            </td>
            <td>
                <div><img data-draggable id="chart_line" src="images2/line.fast.png" title="Line" >Line</div>
            </td>
        </tr>
        <tr>
            <td>
                <img data-draggable id="chart_pie" src="images2/pie.png" title="Pie" alt="Pie" width="64" height="64">Pie
            </td>
            <td><img data-draggable id="chart_area" src="images2/area.png"  title="Area" alt="Area" width="64" height="64">Area</td>            
        </tr>
        <tr>
            <td>
                <img data-draggable id="chart_scatter" src="images2/point.png" title="Scatter" width="64" height="64">Scatter
            </td>
            <td>
                <img data-draggable id="chart_bubble" src="images2/bubble.png" title="Bubble" width="64" height="64">Bubble
            </td>
        </tr>                        
            
    </table>  

And here is the AngularJS ng-repeat generated table.

FYI: ng-class assigns the image-border class if the initImage values are equal. ng-click goes into the controller and reassigns the chart based on what was just selected.

PROBLEM: I cannot figure out how to select a NEW chart icon with red border, and simultaneously REMOVE the image-border class on the others.

(function () {
    'use strict';
    angular.module('rage')
       .controller('GadgetIconsCtrl', ['$rootScope', '$scope',  icons]);

    function icons($rootScope, $scope) {

        var gadgets = this;

        gadgets.subset = null;
        gadgets.chartSelected = null;

        gadgets.selectChart = function (chart) {
            // the assumption is that user selected a different chart icon from the formatting tab
            gadgets.chartSelected = chart;
        };
        
        if ($scope.widget.gadgetType == 'chart' && $scope.widget.chartType == 'bar') {
            // user is configuring a bar chart type, so we also include 'column' in our subset of icons to display
            gadgets.subset = _.filter($scope.widgetDefs, function (item) {
                return item.chartType == 'bar' || item.chartType == 'column';
            });
        }
    };   // end of gridSettings()    
})();
<style scoped>
    .image-clicked {
        border: 2px solid red;
    }
    .image-unclicked {
        border: 2px solid red;
    }
    
</style>
<table ng-controller="GadgetIconsCtrl as gadgets" >
            <tr ng-repeat="gadget in gadgets.subset"  >
                <td>
                    <!-- the image icon for this widget should have a css border, otherwise none -->
                    <div ng-class="{'image-border': gadget.initImage===widget.initImage}">
                        <img ng-click="gadgets.selectChart(gadget.name)" ng-src="{{gadget.initImage}}" title="{{gadget.title}}" 
                            width="64" height="64">{{gadget.title}}
                    </div>
                </td>
            </tr>
        </table>

I'm sure there's a better Angular approach to this, but I'm still trying to figure out the best use of ng-click and ng-class in this use-case.

Help is appreciated.

thanks, Bob

3
  • I just briefly looked at your code: When do you add click listener on the classes and when is your angular code evaluated? It looks like the ng-repeat html is not yet there. Commented Apr 14, 2015 at 22:42
  • I believe you're right @mrak. In fact, if I add class="image-clicked" at the <table> level, it highlights the whole table. So that tells me that the jquery listener is loading before Angular finished the ng-repeat. I'm working on using ng-click and ng-class instead but having trouble. Commented Apr 14, 2015 at 22:49
  • @mrak - I'm looking at the example called "Animations" at the bottom of this page docs.angularjs.org/api/ng/directive/ngClass Commented Apr 14, 2015 at 22:50

2 Answers 2

2

I started a new plnkr http://plnkr.co/edit/w3Ojy5Eo40QHDtUxJfft for your question.

You can use ng-clik and inject click event (and affected element) into the handler:

$scope.widgetClick = function($event) {
  $event.srcElement.style.border = "2px black solid";
}

Corresponding html:

<div class="image-clicked" ng-click="widgetClick($event)"> ... </div>

For simple dom manipulation, like adding or removing a css class, its better to use angular only instead of mixing things up with jQuery.

Dealing with dom/css changes by yourself is more "jQuery way". With Angular on the other hand, you will change the data for your model and let the framework do the dom/css work.

For your example (using my plunkr code): Define widget for ng-repeat as something like:

{
  title : "Foobar ",
  initImage : "http://lorempixel.com/10/10/",
  clicked: false
}

and change clicked in the handler:

$scope.widgetClick = function(widget) {
  widget.clicked = true;
};

Corresponding html:

<div ng-click="widgetClick(widget)" ng-class="{clicked: widget.clicked}">

The css class .clicked will be added by angular if widget.clicked changes to true.

Why this is better? No Css/Dom manipulation in your code. Everything clean and nice.

EDIT:

How to remove the .clicked class from previously selected widget?

We will need to keep a reference to the selected widget in the controller:

var selectedWidget = null;
$scope.widgetClick = function(w) {
  if(selectedWidget) selectedWidget.clicked = false;
  selectedWidget = w;
  w.clicked = true;
};

Now, when another widget is selected (clicked), we only need to update the model data: Set the clicked property on the previously selected widget to false and change it to true on the selected one. And update the reference to the selectedWidget. Angular will take care about the css. Updated plnkr http://plnkr.co/edit/IqWc1W9N12SH8K72jAun?p=preview

Sign up to request clarification or add additional context in comments.

6 Comments

@bob As I sad, Angular is about data manipulation and not dom manipulation, so stop to think in terms "how to change dom/css" and just change the data :-) So you want the border class to be removed when other widget is clicked? Than change the widget.clicket to false. Done. Hint: Put var selectedWidget; in your controller to know which widget is selected and change widget.selected and selectedWidget in the click handler.
I've updated the plunk to show how "Foobar 95" is the current widget image, and so by default it is selected. plnkr.co/edit/gGD49uKazcRlPzMLe1Dw?p=preview . The other click events to activate/deactive the clicked class is still presenting a problem for me. thank you.
@bob Ok, we are almost there. Why don't you store the widget object in selectedWidget? In the click handler set the clicked property to false for the selectedWidget (if it's not null), set clicked to true for the object which has been selected and update selectedWidget = widget. And keep ng-class="{clicked: widget.clicked}" in the html. Done
By click handler I meant the $scope.widgetClick = function(widget) function. And with selectedWidget myCurrentWidget in your plnkr. Btw you don't have to put this variable into the $scope. So just set myCurrentWidget to widget in the widgetClick function and change the clicked property to true for the widget which is selected and to false for the widget which has been previously selected.
|
2

Try this !! cannot run angular now, but I think it should work!

< script type = "text/javascript" >
  var lastobj = "";

function clickImage(obj, $event) {
  debugger;
  if (lastobj != obj) {
    $(lastobj).css("border", "0px");
  } else {
    $($event.target).css("border", "2px solid red");
  }
};

function clickRow(obj, $event) {

//obj should be the widget
//There you should do similar..
var imageclicked = $($event.target).data('url');
$('.propertyTable td div').css("border", "none");
$($event.target).css("border", "2px solid red");
}); < /script>
<table ng-controller="GadgetIconsCtrl as gadicons">
  <tr ng-repeat="widget in gadicons.widgetSubset">
    <td>
      <div ng-click="clickRow(widget)" class="image-clicked">
        <img data-draggable ng-click="clickImage(widget)" ng-src="{{widget.initImage}}" title="{{widget.title}}" width="64" height="64">{{widget.title}}
      </div>
    </td>
  </tr>
</table>

EDIT I added the unset border functionality u told, and corrected some spelling and grammar mistakes for angularjs. Hope it works!!

4 Comments

Check Also this answer if you want to acces the parameters of the object that generated the row or the image in ng-repeat
I'm getting closer. I amended my code just a couple minutes before I saw your comment. See my ng-class and ng-click above. how do I now REMOVE the red border when I click on something else ?
you refer to another img, for example? check if the evt.target is the focused element.... if not... unset the border ;)
check now! I made some changes. I think now angular spelling and grammar is Ok . Sorry for the "quick response" mistakes

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.