I'm trying to create an app for my Samsung Gear S3 that takes data from an API, dynamically creates a Listview, and propagates it using the data returned via the API. I've got as far as putting the items in the list, but when the page is hidden I want to remove everything from the list. Since I'm doing it programmatically in the first place, there's no easy way such as removing all of the elements using a querySelector and refreshing the Listview.
That said, much how I'm using .addItem - is there a .removeItem or equivalent that isn't documented?
At the moment, I'm listening to the pagebeforehide event and calling .destroy() on the created Listview - which works in the sense that the _items property is cleared but the Listview is still displaying all of the items from before...
The code I have at the moment can be seen below.
(function() {
var page = document.getElementById('search.results'),
listView;
var elems = [ ];
page.addEventListener("pagebeforeshow", function() {
if(sessionStorage.length && sessionStorage.getItem("currentResults")) {
var currentResults = JSON.parse(sessionStorage.getItem("currentResults"));
var elem = document.getElementById("results-list");
listView = tau.widget.Listview(elem, { dataLength: currentResults.length, bufferSize: 10 });
listView.setListItemUpdater(function(listElement, newIndex) {
var data = currentResults[newIndex];
listElement.innerHTML = data.Description;
listElement.id = data.EAN;
});
}
$("li").click(function(e) {
var li = $(e.target);
if(li.attr("id")) {
var EAN = li.attr("id");
tau.changePage("product.html", { name: li.innerHTML, ean: EAN });
}
});
});
page.addEventListener("pagebeforehide", function() {
console.log("page before hide");
if(sessionStorage.length && sessionStorage.getItem("currentResults")) {
console.log(sessionStorage);
sessionStorage.removeItem("currentResults");
console.log(sessionStorage);
}
listView.destroy();
console.log(listView);
});
}());
This list does not actually have an API for removing items or binding to data.
I see you have solved this problem practically by yourself.
I think it is enough to clear the base element of the list now, eg. listView.element.innerHTML = "" or document.getElementById("results-list").innerHTML = "".
I think you can also create issue on https://github.com/Samsung/TAU/issues
because the .destroy() method should remove items which was not attached to widget before widget build.
Related
I'm trying to render a list of images, using RadListView. Being that i had some bizarre behavior when the data was coming from a normal array, i decided to try ObservableArray, as recommended in the docs.(specifically tns-vue)
The problem is, that pushing a new item to the model, doesn't update the view. The item is there, but nothing is shown.
This is my RadListView:
<RadListView layout="grid" ref="newImages" for="image in newImages">
<v-template>
<ImageComponent
showDate="false"
:onLongPress="()=>{onLongPress(image)}"
:image="image"
></ImageComponent>
</v-template>
</RadListView>
The "newImages" array:
data() {
return {
newImages: new ObservableArray([]),
};
}
I add items to the array, using the camera plugin:
openGallery() {
var that = this;
console.log(that.newImages.length);
var context = imagepicker.create({ mode: "multiple" }); // use "multiple" for multiple selection
context
.authorize()
.then(function() {
return context.present();
})
.then(function(selection) {
const images = [];
selection.forEach(function(selected) {
const image = that.createNewFileSchema(selected._android);
images.push(image);
});
that.newImages.push(images)//This adds the images to the array, but UI doesn't respond to the change.
})
.catch(function(e) {
alert(e);
});
},
What could be the problem here?
Your pushing arrays to a data arrays, to make the virtual DOM notice these changes, you probably wan't to use a deep watcher, calling a method returning the updated array.
You would have the same problem with Objects, but then you would be able to use:
this.$set(<object>, <key>, <value>)
I'm unsure if there is a better way for arrays, but you could try a watcher as said
watch: {
newImages: {
handler: function(<value>, <oldValue>) {},
deep: true
}
}
UPDATED - You can use this.$set for arrays
https://v2.vuejs.org/v2/api/#Vue-set
/* this.$set(<Array>, <Index>, <Value>) */
this.$set(this.newImages, this.newImages.length, [...newArrWithImages])
This guy explains reactively updating arrays: Vuejs and Vue.set(), update array
As the title states, I'm trying to read a bunch of nodes under a nested node in Firebase, and display the information using FirebaseAdapter. I'm using the parseSnapshot method to try and grab the information I need but I think I'm misunderstanding exactly how to go about getting the information. The user section of the database is structured like so:
I want only the information under UserInfo, and so I currently have the following code setup to intialize a recyclerview adapter (which gets the information)
private fun setupRequiredRecyclerView() {
val requiredItems = private_items_recycler
val context = this
val userDataRef = mDatabaseReference.child("Users/${prefs.UID}/UserInfo")
val mAdapter = RequiredItemsAdapter(User::class.java, R.layout.privaterecyclerview_item_row, RequiredProfileItemsViewHolder::class.java, userDataRef, context)
//load data into adapter
requiredItems.adapter = mAdapter
//add divider between items
requiredItems.addItemDecoration(Utilities.createDivider(this))
}
But the data snapshot I get back in the parseSnapshot method only seems to contain "dateJoined" and no other nodes, I'm guessing there's something wrong with my reference, but I don't know how to structure it - going up to "Users/UID" gets me everything but it also gets me UserInfoComplete, which I don't want (and as far as I know, there's no way to ignore that data in parseSnapshot, as FirebaseAdapter grabs every child node)
Does anyone out there know how exactly I need to structure my database reference to only get the UserInfo data?
(If necessary, this is my current parseSnapshot method):
override fun parseSnapshot(snapshot: DataSnapshot?): User {
lateinit var user : User
Log.i("Snapshot Data", snapshot!!.value.toString())
var dateJoined = snapshot!!.value
var dateOfBirth = snapshot.child("dateOfBirth").value
var gender = snapshot.child("Gender").value
var location = snapshot.child("Location").value
var phoneNumber = snapshot.child("phoneNumber").value
Log.i("Snapshot Data", snapshot!!.value.toString())
user.dateJoined = dateJoined as Long
return user
}
I'm new in SAPUI5 development and I'd like to know how can I navigate through different apps definitions.
In my case, I'm developing a mobile app that uses the sap.m.App and in some views I'd like to use sap.m.splitApp.
First, I have a login page and a tile container with some options. Depending on the user's choice, I'm showing an splitApp with master and detail page.
Main App Controller: With this method I can navigate to my splitApp view
toApp: function (pageId, context) {
var app = this.getView().app;
// load page on demand
var master = ("Login" === pageId);
if (app.getPage(pageId, master) === null) {
var page = sap.ui.view({
id : pageId,
viewName : "view." + pageId,
type : "JS",
viewData : { component : this }
});
page.getController().nav = this;
app.addPage(page, true);
console.log("app controller > loaded page: " + pageId);
}
// show the page
app.to(pageId);
// set data context on the page
if (context) {
var page = app.getPage(pageId);
page.setBindingContext(context);
}
},
Ticket.view.js: Here I add my master and detail pages to my App
createContent : function(oController) {
// to avoid scroll bars on desktop the root view must be set to block display
this.setDisplayBlock(true);
// create app
this.app = new sap.m.SplitApp();
// load the master page
var master = sap.ui.xmlview("MyTicketsList", "view.MyTicketsList");
master.getController().nav = this.getController();
this.app.addPage(master, true);
// load the empty page
var empty = sap.ui.xmlview("Empty", "view.Empty");
this.app.addPage(empty, false);
return this.app;
}
And it's working fine. I can navigate to my splitApp. The problem is that I have to go back to my Main page (with the tile container) in case the user choice other option. I hope to do that using the following method in my Ticket.controller.js
back : function (pageId) {
this.getView().app.backToPage(pageId);
}
And, on the MyTicketsList controller, I did the handleNavButtonPress using:
this.nav.back("MainPage");
But this, doesn't work!
How can I navigate through apps? Or, perhaps, How is the better way to create my splitter pages view, with Master and Detail pages?
P.S.: I'm following this tutorial
Thanks in advance!
In the splitApp first you should instantiate the view as
oSplitApp.addDetailPage(your view);
then to navigate from the splitapp use,
oSplitApp.toDetailPage(your view);
It's easier than it appears.
I had the same problem and to make the SplitApp preview you just have to call the view like a normal XML view but Insert the TAG
onInit: function() {
this.bus = sap.ui.component(sap.ui.core.Component.getOwnerIdFor(this.getView())).getEventBus();
},
doNavBack: function(event) {
this.bus.publish("nav", "to", {id : "Page1"});
},
I'm working with Titanium SDK 2.1.3 and developing for both iOS 6.1 and Android 4.0.
My application has a TableView, each TableViewRow represents a file and has a custom property called lockedStatus that can be either true or false, when a row is clicked, depending on the value of lockedStatus, a window is opened indicating the state of the element of the row. In this window I can modify the lockedStatus from true to false and viceversa.
The problem I'm having is that in Android the changes done to this property are ignored, unless a completely force the application to stop, this doesn't happen in iOS.
To change the lockedStatus value in the window, I fire an event like this:
Ti.App.fireEvent('updateLockedStatus', {
lockedStatus : true //this can be true or false
});
Then the listener is like this:
Ti.App.addEventListener('updateLockedStatus', function(e){
var rows = table.data[0].rows;
for (var i = 0; i < rows.length; i++) //iterate through the rows to look for the file
{
if (rows[i].fileID == currentlyEditingFile)
{
rows[i].updateLockedStatus(e.lockedStatus);
files[currentlyEditingFile].lockedStatus = e.lockedStatus; //update the file lockedStatus
rows[i].fileObject = files[currentlyEditingFile];
saveFilesToDatabase();
}
}
});
Each row is generated with a updateLockedStatus function, that has the following definition:
row.updateLockedStatus = function(lockedStatus)
{
row.lockedStatus = lockedStatus;
}
The saveFilesToDatabase function looks like this:
function saveFilesToDatabase()
{
var tempFilesArray = [];
for(var i=0;i<filesIds.length;i++)
{
tempFilesArray.push(files[filesIds[i]]);
}
Ti.App.Properties.setString('filesApp', JSON.stringify(tempFilesArray)); //save the file values in the application properties
}
What I mean by being ignored is that when I exit the window and return to the view with the table of files, if I click again on the file I just modified, the window will be opened as if no change had been done.
How can I force an update for all of the contents in the TableView? In iOS there's no problem, but with Android this isn't updated unless I close the application.
Any help will be appreciated.
try using Ti.API.fireEvent & Ti.API.addEventListener instead of Ti.App
you would take care when doing this :
Each row is generated with a updateLockedStatus function, that has the following definition:
row.updateLockedStatus = function(lockedStatus)
{
row.lockedStatus = lockedStatus;
};
If the code above is put in a loop then executing the row.updateLockedStatus may affect only the last row because the row variable gets reused and contains at the end only the last row object. Take a look at this
You can simply use this code :
row.updateLockedStatus = function(lockedStatus)
{
this.lockedStatus = lockedStatus; // this is the current row
};
Or using closures, something like that :
row.updateLockedStatus = (function(r){
return function(lockedStatus){
r.lockedStatus = lockedStatus; // r is the current row
};
})(row);
the local r variable should retain the right row object.
BTW, when you listen events using Ti.App, you should use variables for handlers. Instead of doing this :
Ti.App.addEventListener('updateLockedStatus', function(e){
use this way
var updateLockedStatusHandler = function(e){
//...
};
Ti.App.addEventListener('updateLockedStatus', updateLockedStatusHandler);
Then this could be useful to remove the handler and avoid a potential memory leak :
Ti.App.removeEventListener('updateLockedStatus', updateLockedStatusHandler);
I am currently trying to use the new approach of using FlexGlobals to access an ArrayCollection that I have on the Default view of a mobile application I am developing. Below is the code that makes up the creation and population of that array on the Default view which happens as soon as the app is initiated:
private var ids:ArrayCollection = new ArrayCollection();
private function loop():void
{
var index:int;
for( index = 0; index < compsCollection.length; index++ )
{
trace( "Element " + index + " is " + compsCollection[index].comp_id );
trace( ids.length);
ids.addItem(compsCollection[index].comp_id);
}
}
Now when this code is run i can clearly see from the console that the "ids" ArrayCollection is being populated correctly. Now on a different view within the app I want to access this data and use it for various things. I have used the code below to try and access the data for the ArrayCollection:
protected var ids_list:ArrayCollection = new ArrayCollection();
protected function view1_viewActivateHandler(event:ViewNavigatorEvent):void
{
var obj:Object = FlexGlobals.topLevelApplication.parameters;
ids_list.source = obj.ids;
trace(ids_list.length);
}
When i tried this i do not get an error however the Trace statement returns "0". So I also tried:
protected function view1_viewActivateHandler(event:ViewNavigatorEvent):void
{
ids_list.source = FlexGlobals.topLevelApplication.parameters.ids;
trace(ids_list.length);
}
Which again returned "0" in the trace statement. I finally tried this to see if it would work:
protected function view1_viewActivateHandler(event:ViewNavigatorEvent):void
{
ids_list.source = FlexGlobals.topLevelApplication.ids;
trace(ids_list.length);
}
When I tried this and navigated to the view where this code would be initated I got this error:
Error #1069: Property ids not found on Main and there is no default value.
I could only assume that the ArrayCollection I had created in my default view has no value once I navigate away from it. Is there anyway anyone can please help me with this as there seems to be next to no documentation on how to do these types of things with FlexGlobals? Thanks
You can't access a private property, try it
/*
Replace
private var ids:ArrayCollection = new ArrayCollection();
by
*/
private var _ids:ArrayCollection = new ArrayCollection();
public set ids(value:ArrayCollection):void{
_ids = value;
}
public get ids():ArrayCollection{
return _ids
}
It's extremely bad practice for a child component to know anything at all about the structure of its parent/ancestor. That being said, the reason you can't see the value of the Application's member variable is because you've made it private. If you want it to be visible outside its own scope, you need to make it public.
Pass the ArrayCollection as a property to your view from the main application.