Titanium alloy: I want to add and delete rows from one window and it will automatically update in second window - titanium

i have two xml files..index.xmland win2.xml and both windows have tableview with same content in the rows i mean to say:
index.xml
<Alloy>
<Window backgroundColor="red" >
<ScrollView id="scrollview" >
<TableView id="table" >
<TableViewRow title="Capsicum" onClick="select"></TableViewRow>
<TableViewRow title="Beans" onClick="select" ></TableViewRow>
<TableViewRow title="Spinach" onClick="select"></TableViewRow>
<TableViewRow title="Pizza" onClick="select"></TableViewRow>
<TableViewRow title="Burger" onClick="select"></TableViewRow>
</TableView>
</View>
</ScrollView>
</Window>
index.js
function select(e) {
if (e.row.hasCheck) {
e.row.hasCheck = false;
} else {
e.row.hasCheck= true;
}
}
$.index.open();
win2.xml
<Alloy>
<Window backgroundColor="red" id="win2">
<TableView id="tableView" >
<TableViewRow title="Capsicum" onClick="select"></TableViewRow>
<TableViewRow title="Beans" onClick="select" ></TableViewRow>
<TableViewRow title="Spinach" onClick="select"></TableViewRow>
<TableViewRow title="Pizza" onClick="select"></TableViewRow>
<TableViewRow title="Burger" onClick="select"></TableViewRow>
</TableView>
<TextField id="textfield" returnKeyType="Ti.UI.RETURNKEY_DONE" onReturn="addRow" class="insertField" hintText="Add ingredients"></TextField>
<Button id="removeButton" onClick="removeRow"></Button>
</Window>
</Alloy>
win2.js
function select(e) {
if (e.row.hasCheck) {
e.row.hasCheck = false;
} else {
e.row.hasCheck= true;
}
}
function addRow(){
var myTextFieldValue = $.textfield.value.trim();
if (myTextFieldValue != "") {
$.tableView.appendRow( Ti.UI.createTableViewRow({title:myTextFieldValue}) );
}
}
function removeRow() {
// first get all sections of table which will be first section in your case
var sections = $.tableView.sections;
// perform this check to make your code error free when there are no rows added to tableview.
if (sections.length !== 0) {
var rows = sections[0].rows;
var totalRows = rows.length;
if (totalRows !== 0) {
// now delete all rows which has uncheck=true
for (var i=0; i<totalRows; i++) {
var tempCurrentRow = rows[i];
if (tempCurrentRow.hasCheck) {
$.tableView.deleteRow(tempCurrentRow);
}
}
}
}
}
Now if i add or delete any element from win2.xml or second window it will also delete from or add in index.xml or first window...
Note:
i only want to delete the checked elements i.e hasCheck=true from second window and when i add some new element then i will be able to check them like old elementsLike This
can we create a single tableview and access in both windows?

Like #Rene Pot is saying you could use data binding or if it is too much you could just share the data via a file or property.
You would need to create a JSON object out of your data and the parse this data to create the table. Once you change the data inside the table you apply all the changes to the JSON object. When you open your windows you create the table out of that data.
initial data:
var myData = [{"name":"Item name 1", "checked": true,..}, {"name":"Item name 2", "checked": false,..}, ...];
Ti.App.Properties.setObject("myData", myData);
now in your two other controllers:
var myData = Ti.App.Properties.getObject("myData", []); // this will receiv myData or {}
Now myData has all elements and you would create the table out of this array.
When you change row 0 to be checked you change myData[0].checked=true/false;. At the end you do a Ti.App.Properties.setObject("myData", myData) again to store the data.
If you have much data or want to keep it even if the users clears the app cache/storage you could save myData into a file and read it again instead of getObject.
For the future:
Using data binding/models will help you to get rid of all these manual updates. When you change data all connected elements will update

Related

Titanium Appcelerator (Alloy): I want to add and delete from tableview

i fill data in the textfield when i press done on android keyboard it will enter the data in the tableviewrow but i dont know how?
i did it on button click
and second question is : i want to delete the data on button click whose
row has
hasCheck=true
i mean to say these rows on button click
index.xml
<TableView id="table">
<TableViewRow title="Capsicum" onClick="select"></TableViewRow>
<TableViewRow title="Beans" onClick="select"></TableViewRow>
<TableViewRow title="Spinach" onClick="select"></TableViewRow>
<TableViewRow title="Pizza" onClick="select"></TableViewRow>
<TableViewRow title="Burger" onClick="select"></TableViewRow>
</TableView>
<TextField id="textfield" class="insertField" hintText="Add ingredients"></TextField>
<Button id="addButton" title="Add" onClick="addRow" ></Button>
<Button id="removeButton" title="Remove" onClick="removeRow" ></Button>
</Window>
index.js file
function addRow(){
var myTextFieldValue = $.textfield.getValue();
var row=Ti.UI.createTableViewRow({title:myTextFieldValue});
$.table.appendRow(row);
}
function select(e) {
if (e.row.hasCheck) {
e.row.hasCheck = false;
} else {
e.row.hasCheck= true;
}
}
It's pretty simple if you properly follow the Appc Docs:
Answer for Query 1:
There's an event called return for TextField proxies which is called when you press Done button or Return button on iOS or Android. But the title of this Return button can be anything as specified here: Return Key Title
So, you have to make below changes in TextField node to make it work on pressing enter on keyboard, like this:
<TextField id="textfield" returnKeyType="Ti.UI.RETURNKEY_DONE" onReturn="addRow" class="insertField" hintText="Add ingredients" />
Answer for Query 2:
You will have to fetch all rows from table which is a bit lengthy because you cannot directly fetch rows from TableView, rather you will first need to fetch the first section of TableView & then rows from section.
Note: If you do not add any section in TableView, then by default Titanium adds a single section in TableView and add rows in this section. This is why you need to take care of getting the first section first.
Here's the code to delete all checked-rows on Remove button click.
function removeRow() {
// first get all sections of table which will be first section in your case
var sections = $.table.sections;
// perform this check to make your code error free when there are no rows added to tableview.
if (sections.length !== 0) {
var rows = sections[0].rows;
var totalRows = rows.length;
if (totalRows !== 0) {
// now delete all rows which has uncheck=true
for (var i=0; i<totalRows; i++) {
var tempCurrentRow = rows[i];
if (tempCurrentRow.hasCheck) {
$.table.deleteRow(tempCurrentRow);
}
}
}
}
}
Just a minor change in your adding code so that you don't accidentally add empty title rows:
function addRow(){
var myTextFieldValue = $.textfield.value.trim();
if (myTextFieldValue != "") {
$.table.appendRow( Ti.UI.createTableViewRow({title:myTextFieldValue}) );
}
}

Nativescript TextField add char while typing in

I need to add one char the the TextField while also typing in. I get typed chars from View Model Object.defineProperty getter/setter. What do I should do?
I would recommend going through this article in order to receive better answers. One important thing is to show us a code you are working with and what you have tried so far.
As for the question - are you trying to create two-way binding?
if so this is the basic scenario to do it with a text-field:
page.ts
import { EventData, Observable } from "data/observable";
import { Page } from "ui/page";
var vm = new Observable();
vm.set("msg", "default message");
export function navigatingTo(args: EventData) {
var page = <Page>args.object;
page.bindingContext = vm;
}
page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
<StackLayout>
<TextView hint="" text="{{ msg }}" editable="true" />
<TextField hint="" text="{{ msg }}" />
</StackLayout>
</Page>

Titanium scrollable view index

My project is to list products with a views, then when click on a product i have to go to another page and re-list the products with scrollableview and target the clicked view to be displayed first (sorry for bad english):
Let's say this is my list (Grabbed from a collection) :
<Alloy>
<Window id="products" onClose="cleanup" title="All products" class="container" >
<ScrollView dataCollection="list_products" dataTransform="parse_liste" layout='vertical' id="results" class="resultats">
<View product_id="{ID}"
product_photo="{photo}"
product_name="{product_name}" lauyout='horizontal' class='heightAuto' width='Ti.UI.FILL' backgroundColor='#eee' bottom='1'>
<ImageView touchEnabled="false" left='10' image='{photo}' />
<View touchEnabled="false" layout='vertical' height='Ti.UI.SIZE'>
<Label touchEnabled="false" left='100' class='nom' text='{product_name}' />
<Label touchEnabled="false" left='100' class='nom' text='{product_price} €/h' />
</View>
</View>
</ScrollView>
<ActivityIndicator color="white" id="activityIndicator" message="Chargement des candidats ..."/>
</Window>
When click on product (the controller) :
var products = Alloy.Collections.liste_recherche;
$.activityIndicator.show();
products.fetch({
success:function(model,results){
Alloy.Globals.results = results;
$.activityIndicator.hide();
}
});
//// CLICK ON A PRODUCT
$.list_products.addEventListener('click', function(e){
if( Alloy.Globals.results ){
///////// GO TO PRODUCT PAGE AND PASS ARGS
var xpng = require('xpng');
xpng.openWin(Alloy.CFG.nav, 'product', Alloy.Globals.products);
}
});
The product page :
var args = $.args;
function getProfil(){
var products_array = [];
var c = ['gray','green','blue','red'];
_.each(args, function(item, key, value){
/* Créer la vue */
var product_container = Ti.UI.createView({
id:item.ID,
layout:'vertical',
backgroundColor:c[Math.floor(Math.random() * c.length)]
});
var product_image = Ti.UI.createImageView({ image : item.photo});
var product_name = Ti.UI.createLabel({
text: item.champs_candidat.nom
});
product_container.add(product_image);
product_container.add(product_name);
products_array.push(product_container);
});
var style = $.createStyle({
classes: ['listeProfiles'],
apiName: 'ScrollableView'
});
var product_scroller = Ti.UI.createScrollableView({
className: 'listeProfiles',
views : products_array,
showPagingControl:true
});
product_scroller.applyProperties(style);
$.product_win.add(product_scroller);
}
Those codes works fine, just i want to display clicked view (from page A) first.
Thank you for help.
I think you need to capture which view was clicked on ScrollView click event:
$.list_products.addEventListener('click', function(e){
// e.source will give you the clicked view and will behave like $.VIEW_ID
// so you can access any property or method of the clicked view using e.source here
Ti.API.info("Clicked View ID = " + e.source.product_id);
if( Alloy.Globals.results ){
///////// GO TO PRODUCT PAGE AND PASS ARGS
var xpng = require('xpng');
xpng.openWin(Alloy.CFG.nav, 'product', Alloy.Globals.products);
}
});
As per your code, you have already disabled the touches of child-views of the view with this property product_id, so the above modified click event code will be able to provide you the correct product ID of the clicked View inside the ScrollView.
Now:
You have the product_id of the view clicked.
Write code on your collection data to know the index of that
product_id.
Use the index from step 2 to set this property currentPage of ScrollableView
Here is the summary of overall process:
Get the product_id of the clicked view using e.source
Use this product_id to know its index in data collection.
Finally, index from step 2 will be the value of currentPage property of ScrollableView. (it's your preference how you pass this index to product page.)

Nativescript can't get slide event

how can I get the slide event for slider ? I tried
slider.on('slide', function(){
console.log('slide!');
});
and
slider.on('change', function(){
console.log('slide!');
});
but it doesnt work :(( Thanks in advance.
Bind the slide value to an observable object and then listen to the propertyChangeEvent of that object.
Example
Given you have an XML looking like this:
<Page loaded="pageLoaded">
<StackLayout>
<Slider value="{{ sliderValue }}" />
</StackLayout>
</Page>
Then you can write your binding and event like this:
var observable = require("data/observable");
function pageLoaded(args) {
var page = args.object;
var viewModel = new observable.Observable();
viewModel.set('sliderValue', 42);
page.bindingContext = viewModel;
viewModel.on(observable.Observable.propertyChangeEvent, function(propertyChangeData){
//Do your magic here
});
}
exports.pageLoaded = pageLoaded;
Data bindings and Observable Objects are key parts of NativeScript. I highly recommend reading the documentation and get yourself familiar with them:
https://docs.nativescript.org/bindings.html
https://docs.nativescript.org/ApiReference/data/observable/HOW-TO.html

How to handle dynamic creation of view in alloy xml

I have very simple view index.xml
<Alloy>
<Window id="byFav">
<TableView id="tableByFav" />
</Window>
<Alloy>
in this program I want to open webView and use this instead of tableByFav View
when you click tableByFav.
I am not sure how to describe this process in xml.
So I write code in index.js like this.
$.tableByFav.addEventlistener('click',function(e){
entryWindow = Titanium.UI.createWindow({
title: "window"
});
entryView = Titanium.UI.createWebView({
url: "google.com"
});
entryWindow.add( entryView );
$.byFav.open( entryWindow );
}
However I am not sure it is obeying the concept of alloy.
I am trying to understand the concept of alloy.
You are opening the wrong window, try this instead:
$.tableByFav.addEventlistener('click',function(e){
var entryWindow = Titanium.UI.createWindow({
title: "window"
});
var entryView = Titanium.UI.createWebView({
url: "http://www.google.com"
});
entryWindow.add( entryView );
// Call open on the entry window itself
entryWindow.open({
modal : true // Set to true if you want an opening animation
});
}
To do this with Alloy, you can create a controller for the webview named (entryWindow.xml) like this:
<Alloy>
<Window id="entryWindow">
<WebView id="entryView" />
</Window>
<Alloy>
And the in controller (entryWindow.js) you can set the url from the supplied arguments:
$.entryView.url = arguments[0].url;
Now in your index controller, you would open the webview like this:
$.tableByFav.addEventlistener('click',function(e){
// Create a controller, pass url argument
var controller = Alloy.createController('entryWindow', {url: "http://www.google.com"});
// Get the controller's view (a window) and open it
controller.getView().open({
modal : true // Set to true if you want an opening animation
});
}