View is not updating from other controller Appcelerator Alloy - android

I hope you will be fine.
I am having trouble updating views in Titanium Appcelerator Alloy,
I basically want to be able delete previous children from picker and then add new one in picker that is in a different controller/view that i am currently in.....
I have followed this THIS SOLUTION unfortunately that is not working for me. Here is the code I am trying.
createEvent.js
Ti.App.addEventListener('db_update', function(){
alert("OK");
$.picker.removeAllChildren();
})
customParty.js
$.btnclick.addEventListener('click', function(){
Ti.App.fireEvent('db_update');
});
// OK alert shows up but the children of picker aren't removed.

Since Ok Alert is shown, you are in the good way and the callback function is called successfully.
The problem here is that calling removeAllChildren method is not removing rows from your picker. the solution is to iterate over colums and delete rows like this :
Ti.App.addEventListener('db_update', function(){
alert("OK");
//get picker columns
var columns=$.picker.getColumns();
//Iterate over picker columns
for (var it=0,length=columns.length;i<length;it++){
//iterate over column rows
if(columns[it]){
var len = col.rowCount;
for(var index=0,collength=columns[it].length;index<collength;index++){
//remove rows[index] of columns[it]
columns[it].removeRow(columns[it].rows[index]);
}
}
}
});
By the way Applcelerator's folks said that using global events (Ti.App events) may cause problems in memory managements...
Keep in mind that app-level events are global, which means they remain in context the entire time your app is running (unless you remove them). This also means that any objects they reference will also remain in scope while your app runs. This could prevent those objects from being garbage collected.
Appcelerator Documentation.
Another method is to use global functions:
In your first view controller (where picker is defined):
Alloy.Globals.removeAllPickerChildren=function(){
//do what you want here
};
then in the seconde viewcontroller:
$.btnclick.addEventListener('click', function(){
if(Alloy.Globals.removeAllPickerChildren)
Alloy.Globals.removeAllPickerChildren();
});

Related

How to Repaint FMX Android components in Form in C++Builder 10.4?

I wrote a very simple FMX Adroid App, the function is:
Show Form 2 then write something to record(include title and detail text),
close Form 2 to Main Form, then make a checkbox in Main Form with the title we just recorded in Form 2.
if user check the checkbox, then press "del" buttn then delete the record file and checkbox.
the problem is:
when closed Form 2 and in MainForm::OnActivate we can add a new checkbox for the record.
if we checked checkbox then clicked delete, free the pointer of checked checkbox, the checkbox still in main form until I reopen the APP.
I tried:
Invalidate();
Application->ProcessMessages();
BeginUpdate();
EndUpdate();
Still can't work
does anyone know what's going on ? why FMX TForm member has no "Repaint()" or "Update()" "Refresh()" ? just like VCL has.
If you want your TCheckBox* (or any other control) disappear from a Form, you need to set its Parent property to nullptr before deleting it. If you created your control in runtime using new please remember to call delete.
//init
TCheckBox* checkBox = new TCheckBox(Form2);
//delete
checkBox->Parent = nullptr;
delete checkBox;
Answering the second part of your question, you can call Invalidate() function to repaint your whole Form (but first see first part of this answer). But I think it will run properly without calling this function.
Your controls have Repaint() member and it may be better to call them instead, ie. if your checkbox was placed in TPanel*, repainting only this panel is better idea than repainting whole form.

FMX ListView with LiveBindings

I am developing an FMX (Android) app using a ListView in Delphi 10.2.3. I have the Listview live(bound) to a ClientDataSet with (Synch->*). This works very well, and any changes in Listview are propagated to the ClientDataSet, including the ClientDataSet's event handlers, such as BeforeUpdate, Post and AfterScroll.
Now when I move the record pointer in the ClientDataSet programmatically, the Listview does not synch with the change. It seems the Livebinding only works "one way" (from the UI to the Dataset).
How can I make the Listview follow the ClientDataSet, the way it does in the VCL when using a DataSource?
// here I expect the see the selected item start at the first item
// in the UI in index order and move quickly down through the
// list until it stops at the last one. This doesn't happen. The UI remains
// unaffected.
ClientModule.CDSData.First;
while not ClientModule.CDSData.Eof do
begin
ClientModule.CDSData.Next;
Sleep(100);
end;
The easy answer to this question is to perform a
if ClientModule.CDSData.Locate('PKID', VarArrayOf([PKIDValue]), []) then
It seems that while moving the record pointer using CDSData.Next doesn't sync back to the Live(Bound) Listview, using a locate does.

Add a service to my android app to get notifications whenever a fire base child is added [duplicate]

I have a node in Firebase getting continually updated with information from a logfile. The node is lines/ and each child of lines/ is from a post() so it has a unique ID.
When a client first loads, I want to be able to grab the last X number of entries. I expect I'll do this with once(). From then on, however, I want to use an on() with child_added so that I get all new data. However, child_added gets all data stored in the Firebase and, after the initial setup, only want the new stuff.
I see that I can add a limitToLast() on the on(), but, if I say limitToLast(1) and a flood of entries come in, will my app still get all the new entries? Is there some other way to do this?
You need to include a timestamp property and run a query.
// Get the current timestamp
var now = new Date().getTime();
// Create a query that orders by the timestamp
var query = ref.orderByChild('timestamp').startAt(now);
// Listen for the new children added from that point in time
query.on('child_added', function (snap) {
console.log(snap.val()
});
// When you add this new item it will fire off the query above
ref.push({
title: "hello",
timestamp: Firebase.ServerValue.TIMESTAMP
});
The Firebase SDK has methods for ordering, orderByChild() and methods for creating a range startAt(). When you combine the two you can limit what comes back from Firebase.
I think there is a problem in #David East's solution. He is using the local timestamp which may cause problem if the time is not accurate in client device. Here is my suggested solution (iOS Swift):
Using observeSingleEvent to get the complete data set
Then returned it in reversed order by reversed()
Get the last timestamp by for example data[0].timestamp
Using queryStarting for timestamp
self._dbref.queryOrdered(byChild: "timestamp").queryStarting(atValue: timestamp+1)
.observe(.childAdded, with: {
snapshot in
print(snapshot.value)
})
You have the right idea. child_added should be called only for the new nodes. Without source code it's hard to tell why you get all the data in your child_added event.
You can check the chat demo app to see how they load new chat messages. The use case sounds similar.
https://github.com/firebase/firechat/blob/master/src/js/firechat.js#L347
Here's temporary but quick solution:
// define a boolean
var bool = false;
// fetch the last child nodes from firebase database
ref.limitToLast(1).on("child_added", function(snap) {
if (bool) {
// all the existing child nodes are restricted to enter this area
doSomething(snap.val())
} else {
// set the boolean true to doSomething with newly added child nodes
bool = true;
}
});
Disadvantage: It will load all the child nodes.
Advantage: It will not process existing child nodes but just the newly added child nodes.
limitToLast(1) will do the work.

React Native: Change Component (Text) on Navigator Pop

I'm creating a Component/View that has a list of things to select from similar to a table view.
When I'm in View A I can jump to this table view by doing a navigator push. Once an item is selected I do a pop. However, I'd like a text component in View A to be updated with the appropriate value.
I was thinking of passing a reference to this text component but it doesn't sound right. Any other ways I could achieve that?
I couldn't find any table view that would work on both platforms, let me know if you have any good suggestions.
The React way to achieve this is to pass a callback function to a named attribute, let's say in this case onSelect.
MyParentComponent extends Component {
...
MySelectHandler(value) {
this.setState({
valueSelected: value
});
},
...
}
Creating your picker component:
<MyCustomTableView onSelect={this.MySelectHandler}/>
And in your component:
MyCustomTableView extends Component {
...
onValueSelected(value) {
this.props.onSelect(value);
}
...
}
Considering your "re-render" problem, React only updates Component who have changed depending on the previous state. As your inputs probably don't depend on the state, they don't get updated because nothing changed for them.
If you want to clear all your inputs when the valueSelected key state gets updated, you can use the lifecycle method componentDidUpdate(), and manually clear your inputs after each value update.
// In MyParentComponent
componentDidUpdate(prevProps, prevState) {
if (prevState.valueSelected !== this.state.valueSelected)
this.refs.myInput.value = ''; // Do this for each input, you'll need to add a unique ref attribute for each one
}
...
I solved it by passing {this} to the table view as a prop and calling this.props.parent.setState({selection: selectedThing}) in the table view.
I thought setState would re-render the whole view and get rid of any user inputs but it seems to only re-render changed components

alternative to AlertDialog.builder in while loop?

from what I've read so far, it's bad practice/impossible to loop and have an AlertDialog pop up each time. But I haven't found anything alternatives to satisfy that functionality.
The example is: get a cursor from a DB and loop through each item. while looping through do a comparison on a text field. If they don't equal each other, show an alert to decide what to do ie. append, overwrite or skip the text.
thanks
You could also collect the information and use a list view instead that offers options per conflict. The popup way will drive people mad and nobody is going to use it more than once.
Loop through the cursor to read each element (Here I am considering it to be a list). If the trigger condition is met, set boolean WAITING to true, call showDialog() and finally call a waiting loop. This waiting loop will ensure that the parent for loop waits untill the user responds to the inflated dialog from the showDialog().
for(int count =0 ; count<100 ; count ++)
{
if(List.get(count).ID != InputValue)
{
WAITING=true;
showDialog(List.get(count).ID , InputValue);
while(WAITING);
}
}
In showDialog() first create the Dialog and setCancelable() to false so that user has to click on one of the three buttons(append, overwrite or skip) to disable the dialog. Then handle click events for these three, do the required DB operation and finally set WAITING=false and Hide the dialog. This will resume the parent for loop.
showDialog(String DB_Value, Input)
{
Show Dialog with option Buttons and Set dialog.setCancelable(false);
On click of any of one of the three buttons(append, overwrite or skip)
1. do the required DB action
2. hide the dialog
3. WAITING= false
}
Hope this helps you!

Categories

Resources