Nativescript: ListView itemTap does not fire when there is a button in the ListView.item template

Created on 15 Aug 2015  路  21Comments  路  Source: NativeScript/NativeScript

When a ListView.itemTemplate contains a button element, the itemTap event does not trigger anymore.

test.xml

<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="pageLoaded">
    <ListView items="{{ items }}" itemTap="onTap">
      <ListView.itemTemplate>
        <StackLayout>
          <Label text="{{ $value }}" />
          <Button text="Button" />
        </StackLayout>
      </ListView.itemTemplate>
    </ListView>
</Page>

test.js

var observable = require("data/observable");
var observableArray = require("data/observable-array");

var items = ['one', 'two', 'three', 'four'];
var viewModel = {
    items: items
};

exports.pageLoaded = function (args) {
    var page = args.object;
    page.bindingContext = viewModel;
};

exports.onTap = function (args) {
    var index = args.index;
    console.log('Clicked item with index ' + index);
};

I'm not sure if this is made on purpose, but for me it was very hard to figure out why the itemTap event doesn't fire.

If this behaviour is intended, it should be mentioned in the ListView documentation.

list-view-with-buttons

Most helpful comment

Looks like this is known issue with buttons inside ListView in Android

Here is an example how to do this in {N}:

<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="pageLoaded">
  <ListView items="{{ items }}" itemTap="onTap">
    <ListView.itemTemplate>
      <StackLayout>
        <Label text="{{ $value }}" />
        <Button text="Button" loaded="btnLoaded" />
      </StackLayout>
    </ListView.itemTemplate>
  </ListView>
</Page>
var observable = require("data/observable");
var observableArray = require("data/observable-array");

var items = ['one', 'two', 'three', 'four'];
var viewModel = {
    items: items
};

exports.pageLoaded = function (args) {
    var page = args.object;
    page.bindingContext = viewModel;
};

exports.btnLoaded = function (args) {
    var btn = args.object;
    btn.android.setFocusable(false);
};

exports.onTap = function (args) {
    var index = args.index;
    console.log('Clicked item with index ' + index);
};

All 21 comments

Looks like this is known issue with buttons inside ListView in Android

Here is an example how to do this in {N}:

<Page xmlns="http://www.nativescript.org/tns.xsd" loaded="pageLoaded">
  <ListView items="{{ items }}" itemTap="onTap">
    <ListView.itemTemplate>
      <StackLayout>
        <Label text="{{ $value }}" />
        <Button text="Button" loaded="btnLoaded" />
      </StackLayout>
    </ListView.itemTemplate>
  </ListView>
</Page>
var observable = require("data/observable");
var observableArray = require("data/observable-array");

var items = ['one', 'two', 'three', 'four'];
var viewModel = {
    items: items
};

exports.pageLoaded = function (args) {
    var page = args.object;
    page.bindingContext = viewModel;
};

exports.btnLoaded = function (args) {
    var btn = args.object;
    btn.android.setFocusable(false);
};

exports.onTap = function (args) {
    var index = args.index;
    console.log('Clicked item with index ' + index);
};

Hello @enchev and @tsvetan-ganev,
I have same problems, I have check your tutorial Mr. @enchev, but not works.
Do you have answer about this problem Mr. @tsvetan-ganev ???

@Jayuda, as far as I remember I haven't tried @enchev's workaround, because in the end I just used a label with on-tap event instead of a button.

I can confirm that the workaround by @enchev does work. Thanks! 馃槃

i can't access the current index in my listview template with {{ $value }} any solution?

@Robophil better create new issue with detailed information about the situation you are trying to solve and a sample code/project given (in order to reproduce your case and give the best advice possible)

Thanks. Already solved this.

@Robophil care to share how?

Hi @roblav96, it was an passing an array of objects. when working with just an array of maybe(numbers or string) $value works fine. I just had to access the key of the object in my template view

Ah, gotcha. Thanks for the enlightenment :D

The convo here just helped solve the issue i had. just one more thing, Is there something like an itemTemplateTap that gets the index of the list, just live the itemTap.

sure, you can get the index @dameety

<ListView items="{{ items }}" itemTap="onItemTapped">
function onItemTapped(args){
   const index = args.index;//index of tapped item
}

thanks @Robophil but i get that. i need to get that same index with a button in the listview template. see:

<ListView items="{{ courses }}" itemTap="navigateToSchedule">
<ListView.itemTemplate>
    <StackLayout class="marksLabelStack">
        <DockLayout class="below" orientation="horizontal">
            <Label text="{{ course_name }}" dock="left"/>
            <StackLayout orientation="vertical">
                <Button class="" dock="right" loaded="btnLoaded" text="button" horizontalAlignment="right" tap="REMOVE"/>
            </StackLayout>
        </DockLayout>
    </StackLayout>
</ListView.itemTemplate>
</ListView>

i wanna get the index with the tap="REMOVE"

@dameety you can set the id of the button to the index:

            <StackLayout orientation="vertical">
                <Button id="{{ 'btn_' + $index }}" class="" dock="right" loaded="btnLoaded" text="button" horizontalAlignment="right" tap="REMOVE"/>
            </StackLayout>

Then get the index like so:

function onButtonTapped(args: EventData){
    let index: number = parseInt(args.object.id.slice(-1))
}

Thanks @roblav96 i will try it out soonest.

@roblav96 I tried your suggestion with the following

    <ListView.itemTemplate>
     ...
                    <StackLayout >
                        <Image id="{{ 'btn_' + $value }}" tap="likeItem" class="width-50" />
                    </StackLayout> 
                </StackLayout>
    </ListView.itemTemplate>

Only problem is that as args.object.id I get btn_undefined
Am I doing something wrong?
Thanks for your support :)

You're right this way does not work, nor does the use of $index like it does in ng2. So you'll need to manually insert an index number in your array of objects.

For the likeItem event, you need to add it to your application.resources:

import application = require('application')
application.resources['likeItem'] = function likeItem() {}

use this linke in ur button xml
android:focusable="false"

@Sakshamgupta20 could you please explain in more details how you configure your Nativescript to android:focusable="false" construction works in XML?

If I add it to my button, it does not work

<Button android:focusable="false" text="Tap Me" tap="onButtonTap" />

But if I set it within loaded event (as was suggested in previous comments), then this workaround works. But for me, it is much cleaner to set this property with XML rather than with code.

UPDATED:
I understand this construction from Android, not Nativescript, world.

Rather than fight with buttons or inputs stealing focus and preventing the itemTap from being passed along, it is easier to style a label to look like a button or to look like an input if you purpose is only to view data.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings