Search code examples
htmlangularjspass-by-reference

Pass another element to ng-click


I want to create a list of items, which are simple clickable text. Each time you click on an item it tranforms to an input (textbox) and you can edit it. I have done this already. The only thing I am missing is to set the focus on the input element when I click on the item. My HTML code is the following:

<div ng-repeat="item in items">
  <span ng-if="!valueIsEditedForItem(item.id)">
    <a href="" ng-click="editValueForItem(item.id)">
      {{ item.value }}
    </a>
  </span>
  <span ng-if="valueIsEditedForItem(item.id)">
    <input ng-model="edited_value"
           ng-keyup="onValueInput($event, item.id, edited_value)"/>
  </span>
</div>

The <a> element and the <input> element are two different elements. So, my idea is to pass the input element somehow to the ng-click="editValueForItem(item.id). It should look something like this:

<a href="" ng-click="editValueForItem(item.id, inputElement)">
  {{ item.value }}
</a>

Then I would be able to set the focus to the input element by doing this:

inputElement.focus();

I know that the $event variable holds the element of the event in $event.target. But my event is on <a> and not on <input>. How can I reference the <input> element into <a>?


EDIT: Solution

After reading solution suggestions from the answers, I finally implemented this by referencing by id:

HTML

<input id="{{'input' + item.id}}"
       ng-model="edited_value"
       ng-keyup="onInput($event, item.id, edited_value)"/>

JS

$scope.editValueForItem = function (itemId) {
  $scope.currentlyEditedItemId = itemId;

  // focus on the input element
  setTimeout(function () {
    var inputElement = document.getElementById("input" + itemId);
    if (inputElement) {
      inputElement.focus();
    }
  }, 0);
};

The setTimeout clause is necessary to give priority to the initialization of the element. If you remove it, then the getElementById command will return null, because the input element will not have been initialized yet.

However, the solution with creating my own directive would be a more proper option.


Solution

  • Straight approach is to add some ref, e.g.:

    <input ng-model="edited_value" editable="{{item.id}}"
           ng-keyup="onValueInput($event, item.id, edited_value)"/>
    
    // editValueForItem method
    $timeout(() => angular.element(document.querySelector('[editable="' + itemId + '"]')).focus())
    

    Another might be:

    <input ng-model="edited_value" take-focus-on-init
           ng-keyup="onValueInput($event, item.id, edited_value)"/>
    

    where take-focus-on-init is directive that focus element in link function.

    Third one is to make directive:

    <editable value="item.value"></editable>
    

    with template:

    <div ng-if="!inEditMode">{{item.value}}</div>
    <div ng-if="inEditMode"><input ...</div>
    

    here you can use simple element.find('input').focus()