Javascript Question

nativescript listview item delete from helloworld app

I'm just finished to read and test nativescript helloworld app, and i can't understand, how to delete item by clicking on it.
I'm understand it like i need to get array index after click to make .splice on it, but in args i have now such data??
Please explain me how to do this. Thank you!

tasks.js

var observableModule = require("data/observable");
var observableArray = require("data/observable-array");
var viewModule = require("ui/core/view");

var tasks = new observableArray.ObservableArray([]);
var pageData = new observableModule.Observable();
var page;

exports.onPageLoaded = function(args) {
page = args.object;
pageData.set("task", "");
pageData.set("tasks", tasks);
page.bindingContext = pageData;
};

exports.add = function() {
tasks.push({ name: pageData.get("task") });
pageData.set("task", "");
viewModule.getViewById( page, "task" ).dismissSoftInput();
};

exports.del_first = function() {
tasks.splice(0,1);
viewModule.getViewById( page, "task" ).dismissSoftInput();
console.log('DEL');
};

exports.remove = function(args) {
console.log('REM');
};


tasks.xml

<Page loaded="onPageLoaded">
<GridLayout rows="auto, *">
<StackLayout orientation="horizontal" row="0">
<TextField width="200" text="{{ task }}" hint="Enter a task" id="task" />
<Button text="Add" tap="add"></Button>
<Button text="Delete 1st" tap="del_first"></Button>
</StackLayout>

<ListView items="{{ tasks }}" row="1">
<ListView.itemTemplate>
<StackLayout orientation="horizontal" row="0">
<Label text="{{ name }}" />
<Button text="x" tap="remove"></Button>
</StackLayout>
</ListView.itemTemplate>
</ListView>
</GridLayout>
</Page>

Answer

The issue is that the button has no knowledge of which task to delete. It is not passed any value other than what you passed it, which was the text="x" and the tap="remove".

So, the trick is to assign your own addition value to the button containing the id/index of the task so that you can then match it back to the task. You can use any unassigned name for the button property value and for your object key (I chose to use index="{{ index }}". So deleteId="{{ id }}" would be just as valid.

So the best way to do this currently is with a few minor changes to your code:

tasks.js

var observableModule = require("data/observable");
var observableArray = require("data/observable-array");
var viewModule = require("ui/core/view");

// Pretend we loaded some records, notice the new "index" field?
//  This is what name we use in the xml, so it is: "{{ index }}"
//  Again this name can be anything you want; id, index, guid, uuid, etc...
var _tasks = [{name: 'aaa', index: 0}, {name: 'bbb', index: 1}, 
    {name: 'ccc', index: 2},{name: 'ddd', index: 3},{name: 'eee', index: 4}];

// Simple _index count since I cheated and created a fixed array; 
// the better way would be to enumerate the array 
// and set _index to the highest index found in the array.
var _index = _tasks.length;;

var tasks = new observableArray.ObservableArray(_tasks);
var pageData = new observableModule.Observable();
var page;

exports.onPageLoaded = function(args) {
  page = args.object;
  pageData.set("task", "");
  pageData.set("tasks", tasks);
  page.bindingContext = pageData;
};

exports.add = function() {
  // Note we are creating a new index, always incrementing so that the
  // _index will always be unique.   UUID's would also work.
  var newIndex = ++_index;

  // Push the name and new created index again using the same "index" field
  tasks.push({ name: pageData.get("task"), index: newIndex });
  pageData.set("task", "");
  viewModule.getViewById( page, "task" ).dismissSoftInput();
};

exports.del_first = function() {
  tasks.splice(0,1);
  viewModule.getViewById( page, "task" ).dismissSoftInput();
  console.log('DEL');
};

exports.remove = function(args) {
  // The args is a event packet, with 
  //    eventName = what event occurred 
  //    object = the object this event occurred against
  // So we need to use the target object, 
  //   then we are getting the "index" PROPERTY we assigned on it in the xml
  var target = args.object;
  var index = target.index;

  // Now we search all the tasks, to find the index that matches our
  // index that the button was pressed on.   Then we delete it and break out of the loop.
  for (var i=0;i<tasks.length;i++) {
    if (tasks.getItem(i).index === index) {
        tasks.splice(i,1);
        break;
    }
  }

  console.log('REM');
};

tasks.xml

<Page loaded="onPageLoaded">
  <GridLayout rows="auto, *">
    <StackLayout orientation="horizontal" row="0">
        <TextField width="200" text="{{ task }}" hint="Enter a task" id="task" />
        <Button text="Add" tap="add"></Button>
        <Button text="Delete 1st" tap="del_first"></Button>
    </StackLayout>

    <ListView items="{{ tasks }}" row="1">
        <ListView.itemTemplate>
            <StackLayout orientation="horizontal" row="0">
                <Label text="{{ name }}" />
     <!------------ Notice the new "index" property ----------->
                <Button text="x" index="{{ index }}" tap="remove"/>
            </StackLayout>
        </ListView.itemTemplate>
    </ListView>
  </GridLayout>
</Page>