6

I have a list which populates a screen using ng-repeat. Each row has a button for the user to click on to select the row. Typically what you would use a radio button for but the user wants a button toggle.

What I really want is to show the first button (hide the second on displaying the list first time) and after the user clicks on the first one to select a specific row, I want to hide the first button and show the second. The 2 button have different ids, text, style. So to the user, its like changing the look of the button after selection.

I tried setting the showfarebut1 / showfarebut2 scope variable in my function populateFareOption(row.col3.value, row.col4.value) in the controller, but all the rows had the second button after button one is clicked.

Any ideas or code snippet .. will be appreciated.

HTML

<tr ng-repeat="row in rowList">
    <td> {{row.col1.value}}</td>

    <td>
        <span class="price">PRICE:&nbsp;
            <strong class="amount">{{row.col2.value}}</strong>
        </span>

        <button id="btnXX1" ng-show="showfarebut1" type="button" class="btn pull-right" ng-click="populateFareOption(row.col3.value,row.col4.value)">

            <span class="text pull-left" name="fareOption" ng-model="travelCardForm.colOption" value="{{row.col3.value}}">Select</span>
            <i class="icon-placeholder"></i>
        </button> 

        <button id="btnXX2" ng-show="showfarebut2" type="button" class="btn pull-right">
            <span class="text pull-left">Selected</span>
            <i class="selected-icon pull-right"></i>
        </button>
    </td> 
</tr>

Controller

    $scope.showfarebut1=true;
    $scope.showfarebut2=false;

    $scope.populateFareOption = function(x,y){
         cardForm.fareOption.value=x;
         cardForm.productCode.value=y;
         $scope.showfarebut1=false;
         $scope.showfarebut2=true;
       }
4
  • 3
    You shouldn't have two elements with the same ID - that's what classes are for. Commented Apr 30, 2014 at 16:31
  • Can you share your controller where showfarebut1 and showfarebut2 are created? If you want granularity, you probably need to add a couple of visible properties to the row you are iterating. Commented Apr 30, 2014 at 16:32
  • Thanks jraede and Davin ... I have update the snippet. The buttons now have different IDS. Commented Apr 30, 2014 at 16:41
  • @olatom You should not use static id attribute for elements inside ng-repeat. Consider using dynamic ids like id="btn{{$index}}" or don't use them at all. Otherwise you will have buttons with id="btnXX1" and id="btnXX2" in each row and therefore duplicate IDs, which produces wrong HTML and makes abuse of id attribute usage. Commented Apr 30, 2014 at 17:28

2 Answers 2

6

In your example you have showfarebut1 and showfarebut2 shared across all the rows, that causes one button clicked affect all rows. You should use something bound to the current row: row.showfarebut1 and row.showfarebut2.

However, there is a more efficient way to make toggle buttons. You can reuse the same button and set classes and text according to the state of the record. Here is a simple example:

HTML

<ul class="list-group" ng-controller="ctrl">
  <li class="list-group-item" ng-repeat="row in rowList">
    <span>{{row.col1.value}}</span>
    <span>{{row.col2.value}}</span>
    <button type="button" ng-click="row.selected=!row.selected" class="pull-right btn btn-xs">
      <span ng-class="{'glyphicon':true, 'glyphicon-ok':row.selected, 'glyphicon-plus':!row.selected}"></span>
      {{row.selected?'Selected':''}}
    </button>
  </li>
</ul>

You can use ng-class directive to toggle classes and condition like {{row.selected?'Selected':''}} to toggle text of the button.

JavaScript

angular.module('app', []).
  controller('ctrl', function($scope) {
    $scope.rowList = [{
      col1: { value: 'r1c1'},
      col2: {value: 'r1c2'}
    }, {
      col1: {value: 'r2c1'},
      col2: {value: 'r2c2'}
    }, {
      col1: {value: 'r3c1'},
      col2: {value: 'r3c2'}
    }];
  });

You even don't need some special function for selecting an item, you can do simple things directly in ng-click

Screenshot

enter image description here

Plunker: http://plnkr.co/edit/ZFRIWOe2HxMq8K11FBk4?p=preview


Edit (adapted version):

HTML

<table ng-controller="ctrl" class="table">
  <tr ng-repeat="row in rowList">
    <td>{{row.col1.value}}</td>
    <td>
      <span class="price">PRICE:&nbsp;
        <strong class="amount">{{row.col2.value}}</strong>
      </span>
      <button id="btn{{$index}}"  type="button" class="btn pull-right" ng-click="select(row)">
        <span class="text pull-left" name="fareOption" value="{{row.col3.value}}">{{row.selected?'Selected':'Select'}}</span>
        <i ng-class="{'icon-placeholder':!row.selected, 'selected-icon':row.selected, 'pull-right':row.selected}"></i>
      </button>
    </td> 
  </tr>
</table>

JavaScript

angular.module('app', []).
  controller('ctrl', function($scope) {
    $scope.rowList = [{
      col1: {value: 'Orange'},
      col2: {value: '10'},
      col3: {value: 'x1'},
      col4: {value: 'y1'}
    }, {
      col1: {value: 'Apple'},
      col2: {value: '20'},
      col3: {value: 'x2'},
      col4: {value: 'y2'}
    }, {
      col1: {value: 'Banana'},
      col2: {value: '15'},
      col3: {value: 'x3'},
      col4: {value: 'y3'}
    }];

    $scope.select = function(row) {
      row.selected=!row.selected;
      // Do something with row.col3.value and row.col4.value
    }
  });

Plunker: http://plnkr.co/edit/DdO1zBXxkyXWSLA6Gv2x?p=preview

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

4 Comments

Vadim, I love your code and thanks for the time and expertise . But, I am using ready made style from the web design team and I have to code to the style. If only I can adapt your code to work as expected.
I am also trying the other answer below. Interested in both methods as they will be useful now and or in future development. am I missing something in yours.
@olatom I've added an adapted version that uses your markup and concepts from original answer.
Vadim! You have saved me days of banging my head on the wall. I was able to adopt use code in a few minutes and it semi-works, but I want the ability to be able to select only one button from the list i.e. like a radio button. Please, how would you do this. At the mo you can select multiple. I hope we won't have to discard the code, because its too good to be discarded!
0

Attach showfarebut2 to the object in rowList:

$scope.populateFareOption = function(row){
  cardForm.fareOption.value = row.col3.value;
  cardForm.productCode.value = row.col4.value;
  row.showFareBut2 = true;
}

And your HTML:

<button id="btnXX2" ng-show="row.showfarebut2" type="button" class="btn pull-right">

1 Comment

I have tried your logic but can get it to work. The ng-show for each row should have an expression that evaluates to a true or false. When , the page is first loaded a want the first button displayed hence a true ng-show value for the first and second should be false by default. My problem is when the button is clicked your "row.showFareBut2 = true" above is not a scope object and how will it populate the ng-show for the second button. Besides, how do I change the ng-show for first. I must be missing something.

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.