ListView.refresh() no longer updates display of changed items - nativescript

All of a sudden, ListView.refresh() no longer updates the display of the items in the list. I have verified that it has stopped working on previous projects which have been tested and committed. This occurs on both Android and iOS, and on all devices and emulators.
I've done the usual - done an ns clean, rebooted the machine, stated with fresh emulators, and I cannot get any refresh() to work. I've stepped through the refresh() source code in the debugger, and no errors occur, but then this code hasn't changed either.
This is a NativeScript 8 JavaScript project. This problem appeared when using nativescript-ui-listview 10.0.2. The problem persists with version 10.2.8, which is the latest.
I'm at a loss for where to even start. It would appear to be related to my system since prior working code now fails (no error, the list display just remains unchanged). Since it occurs on Android, I presume it's not an Xcode issue.
I'm looking for a lifeline here. Any ideas on what might be going on?
Edit Sep 12, 2022:
I created a fresh Hello World javascript project and added a simple RadListView:
<lv:RadListView id="testview" items="{{ items }}" >
<lv:RadListView.itemTemplate>
<GridLayout columns="2*,*">
<Label col="0" class="mx-16-8 my-0-0" style="font-size: 16" text="{{ name }}" />
<Label col="1" class="mx-8-16 my-0-0" style="font-size: 16" text="{{ count }}" />
</GridLayout>
</lv:RadListView.itemTemplate>
</lv:RadListView>
<Button text="Update" tap="onUpdateTap" />
With the associated code:
viewModel.items = [
{name: "David", count: 8},
{name: "Penny", count: 6},
{name: "Kumar", count: 3},
]
export function onUpdateTap(args) {
let button = args.object;
let page = button.page;
let viewModel = page.bindingContext;
let listview = page.getViewById("testview");
viewModel.items[1].count++;
listview.refresh();
}
This works correctly: the Update button increments the second count and the display is refreshed.
I then added this same code to my working project. It works on iOS devices and emulators but fails on Android devices and emulators. Again, no exceptions, errors, or messages, the display just fails to refresh. This is the only problem isolation I've been able to achieve so far.
I've spent about a day stepping through the ListView.refresh() code in a debugger, but that hasn't yet yielded any paths to pursue. I can see there are three events that are triggered:
dataPopulated
itemLoadingInternal
itemLoading
But, I can't see where those events are handled. Where it works (sample code on iOS), I can see that refresh() returns control before the display is updated. Where it doesn't work, control is returned but there's no update. Otherwise, I can't find any differences between the two flows.
I'm still looking for pointers and hope this additional info will help.
Edit Sep 13, 2022:
On the recommendation from the discord community, I'm looking at using an ObservableArray rather than a simple Array, as that seems better suited for RadListView. But, even this simple code fails to refresh on Android (it works on iOS):
<lv:RadListView items="{{ rlvItems }}" >
<lv:RadListView.itemTemplate>
<GridLayout columns="2*,*">
<Label col="0" class="mx-16-8 my-0-0" style="font-size: 16" text="{{ name }}" />
<Label col="1" class="mx-8-16 my-0-0" style="font-size: 16" text="{{ count }}" />
</GridLayout>
</lv:RadListView.itemTemplate>
</lv:RadListView>
viewModel.rlvItems = new ObservableArray(
{name: "David", count: 8},
{name: "Penny", count: 6},
{name: "Kumar", count: 3}
);
let item = viewModel.rlvItems.getItem(1);
item.count++;
viewModel.rlvItems.setItem(1,item);
I'm concluding that something in my project must be interfering with the value changed notification process; I don't think there's anything wrong with this code or the underlying NativeScript/RadListView code.
I still welcome pointers on what to pursue here.

I was ultimately able to resolve this with an ObservableArray, but not with the code I had listed above. I found no documentation on using a ObservableArray of objects with RadListView and spent 2-3 days trying to get this to work:
let item = viewModel.rlvItems.getItem(1);
item.count++;
viewModel.rlvItems.setItem(1,item);
It turns out that the object is already changed, and thus setItem doesn't detect a change and update the display. I had to use the spread operator to create a new object, and that worked:
let item = viewModel.rlvItems.getItem(1);
item.count++;
viewModel.rlvItems.setItem(1,{...item});
This seems like a hack, and maybe it simply bypasses some other error, but it works for me. I never was able to determine why the original code began to fail.

Related

How to create LibVLCSharp custom playback controls in Xamarin Forms?

I've been searching for days now for a guide on how to create the custom playback controls for LibVLCSharp that everyone seems to talk about, which I never found a guid for.
I simply want to create other buttons with event handlers for the bottom playback control panel, I tried this but throws a System.NullReferenceException exception on startup while getting into break mode...
<vlc:MediaPlayerElement MediaPlayer="{Binding MediaPlayer}" LibVLC="{Binding LibVLC}">
<vlc:MediaPlayerElement.PlaybackControls>
<vlc:PlaybackControls>
<vlc:PlaybackControls.ControlTemplate>
<ControlTemplate>
<Grid>
<StackLayout Orientation="Horizontal" HorizontalOptions="CenterAndExpand">
<Button Grid.Column="0" Text="Test 1"/>
<Button Grid.Column="1" Text="Test 1"/>
<Button Grid.Column="2" Text="Test 1"/>
</StackLayout>
</Grid>
</ControlTemplate>
</vlc:PlaybackControls.ControlTemplate>
</vlc:PlaybackControls>
</vlc:MediaPlayerElement.PlaybackControls>
</vlc:MediaPlayerElement>
I want it to act just like the original one (Auto hides, overlays on tapping, etc...) but with my own layout and controls. I also thought about using the existing one and try to override their handler to implement my own code and override the text property for each button to change its icon but no luck of finding any help.
Thanks in advance ^_^
The code you are interested in is here: https://code.videolan.org/videolan/LibVLCSharp/-/blob/3.x/src/LibVLCSharp.Forms/Shared/Themes/Generic.xaml
I also thought about using the existing one and try to override their handler to implement my own code and override the text property for each button to change its icon
That'd be the way to go.
This previous SO question might answer your question: https://stackoverflow.com/a/14217500/4064749
Just create a new Style based on PlaybackControlsStyle, override what you want and then set it on the PlaybackControls element.
I created https://code.videolan.org/videolan/LibVLCSharp/-/issues/309 recently to track the need of a tutorial to customize the MediaElement.
Further docs on style inheritance: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/styles/xaml/inheritance
I finally found the problem which was making exceptions, when I create custom control template which completely correct, the MediaPlayerElement code behind by LibVLCSharp developers itself cannot find the elements with the names defined anymore as they used hardcoded names for the buttons and views instead of using bindings and dynamic setters.
Thus, several workarounds could be made to fix such issue, here are some of my ideas:
Use the generic style documented here and modify it without removing any elements but rather hide them out or overlay them.
Create your own style with controls obtaining the same names of the original ones.
Find a way to modify or maybe create a whole new playback control element using the original one which can be found here and here.
Thanks to mfkl's answer which helped me find out how everything worked under the hood to come up with the explaination, even though this took me a couple of days to figure out.

react-bootstrap bsClass getting set incorrectly when built in production mode

I'm running into a problem where dropdown menus are displaying incorrectly after building react-bootstrap in production mode:
Upon closer inspection it looks like the HTML is being loaded with the wrong class: <ul role="menu" class="super-colors -menu" aria-labelledby="dropdown-custom-1">. In this case the class should be dropdown-menu and not -menu.
When I inspect the props elements it looks like this is being caused by bsClass being set incorrectly:
{
"className": "super-colors",
"bsRole": "menu",
"pullRight": false,
"bsClass": "-menu",
"open": false,
"labelledBy": "dropdown-custom-1",
"onClose": "[function bound ]",
"onSelect": "[function ]",
"rootCloseEvent": "mousedown"
}
For reference, here is the code for the element shown above:
<ButtonToolbar>
<Dropdown
id="dropdown-custom-1"
onToggle={() => console.log('hi')}
rootCloseEvent="mousedown"
>
<Dropdown.Toggle>Pow! Zoom!</Dropdown.Toggle>
<Dropdown.Menu className="super-colors">
<MenuItem eventKey="1">Action</MenuItem>
<MenuItem eventKey="2">Another action</MenuItem>
<MenuItem eventKey="3" active>
Active Item
</MenuItem>
<MenuItem divider />
<MenuItem eventKey="4">Separated link</MenuItem>
</Dropdown.Menu>
</Dropdown>
</ButtonToolbar>
Some other (possibly) relevant information:
We're using a UI library called patternfly-react that's built on top of react-bootstrap, but the problem seems to be in react-bootstrap.
The app uses react-bootstrap 0.32.1
This only shows up when the app is built in production mode, dev mode works fine.
We have a fairly unconventional setup where we're running React inside of an Angular 6 app.
Anyone have a clue what might be causing this to happen?
So, this turned out to be an issue with Angular. Disabling build optimizations in angular.json fixed the problem.
"production": {
...
"vendorChunk": false,
"buildOptimizer": false,
The build optimizer reduces the size of the compiled package, so while this solution works, it is not without downsides.

Native script list template binding not working

I cannot make working binding with ListView and template.
<ListView #userListView [items]="usersViewList" (itemTap)="onItemTap($event)">
<template let-user="item" let-i="index">
<GridLayout columns="auto">
<Label [text]="user.name" col="0"></Label>
</GridLayout>
</template>
</ListView>
at cration time user.name is assigned properly, but later if I call.
user.name = "other name";
Nothing happens.
Binding context is set to item in usersViewList correctly. But no changes are propagated to individual list item ever.
Thank for advice!
You can't call user.name "later" (guessing in your code behind component file?).
If you need to access the tapped item you can use the index of the tapped item and then you can grab it from your items array like
usersViewList[index].name
You have also itemTap which provides you with arguments where you8 can directly access the tapped index like show here
The best practice, in this case, is to compare your code with a sample that demonstrates the exact same case. Here you can find one. And many other examples are posted in this section of the same application.

NativeScript MaskedInput databinding

I am trying to use the MaskedInput widget (https://github.com/bthurlow/nativescript-maskedinput) and I am having trouble getting the databinding to work. Here is my code:
<mi:MaskedInput mask="999 999 9999" placeholder="_" text="{{ customer.homephone }}" color="#a8b4b9" />
The above snippet does not display the phone number initially. I am positive the customer.homephone has value in it because
<TextField text="{{ customer.homephone, customer.homephone | phoneConverter() }}" class="value bold" />
displays it correctly. If I replace the text property of the MaskedInput with a hard-coded value, the value is displayed. It seems to me that there is something going on with the databinding. Am I missing something here?
Any ideas are highly appreciated.
Thank you.
You are doing things correctly, but from what I see from the code of that plugin it does not support data binding.

How can I make input/select focus in PhoneGap faster?

Clicking on input elements (text, texarea, select, etc) has a noticeable delay in PhoneGap...is there any way to overcome this?
I understand that the user might be dragging/scrolling when they touch the screen which is why the delay is there and I have been able to overcome this with anchors by using onTouchStart events instead of onClick, but I don't know how to apply the same thing to other inputs.
I'm using jqMobi (a stripped down jQuery framework which rocks!).
It doesn't appear as though you can call .focus() on input elements or .click() on select elements, which was what I tried by tapping into the onTouchStart event like this:
<input type="text" name="email" ontouchstart="$(this).focus();" />
<select name="country" ontouchstart="$(this).click();">...</select>
Any help would really be appreciated!!
The sluggishness is on the device, not in the browser. We're currently targeting iOS and I've experienced the sluggishness on the iPhone 4, 4s, iPad 2 and the new iPad.
If you are using jqUi of jqMobi then that should be already solved.
Otherwise you can activate the $.ui.touchLayer plugin which should solve that and other cross browser and touch related issues.
How to Apply Touch event instead of click. when you are dynamically binding html to dom.
[1] href = "<a class='applymenutouch' data-ele='" + i + "' >";
[2] $('.applymenutouch').on('touchstart', function () { alert(render_submenu_link($(this).attr('data-ele'))); })

Resources