Can't change background color and text of a Button belonging to a ListView item

nativescriptcore

#1

I need a 2-state toggle Button: at each tap, that changes its background color and its text label (color and text). Its implementation is simple and it works correctly when the button belongs to a simple page.
Instead, when the button is put in each element of a simple list (20 elements) it does not change its background color, and only its label text changes, not its color.

Here some code details to check the problem:

    <StackLayout orientation="vertical" >
        <ListView items="{{ items }}" itemTap="onItemTap">
            <ListView.itemTemplate>
                <StackLayout orientation="vertical" class="follow-button">
                    <Button text="Undefined" tap="onTap"/>
                </StackLayout>
            </ListView.itemTemplate>
        </ListView>
    </StackLayout>   

and in js side (‘value’ is used only to demonstration):

    var value = 1;
    exports.onTap = function (args) {
        view  = args.object;
        value = value === 1 ? 0 : 1;
        view.text            = value === 1 ? "button on" : "button off";
        view.backgroundColor = value === 1 ? "red"       : "white";
        view.color           = value === 1 ? "white"     : "red";
    }

Behaviour on a page (correct):

Tap 1
50

Tap2
00

Behaviour on a list (wrong):

Tap 1
35

Tap 2
22

I see that removing or fixing the button text, then button background changes correctly at each tap.

Any suggestion?


#2

Here is the playground demo https://play.nativescript.org/?template=play-js&id=Hms4zb&v=2 I’ve just checked that in Android is ok, problem arises with iOS.


#3

The number one rule I would recommend to follow with ListView is - do not play with your view, always play with your data (bindingContext).

Secondly, it looks like a known issue with {N} ListView. I have implemented the fix here,


#4

Hi @manojdcoder and thanks for your help!

In my real case, the button is a custom component (full-js, extending Button) because it is present in a lot of places (pages, list items etc.) and it embeds its own logic to control both its function and style (border, bg, text, color x 2-cases). Obviously, I don’t want to mix business data with style data. This logic is completely unknown to the caller context where I wave a simple call like:

<FollowButton:FollowButton entityId="{{ itemId }}" entityType="customer" value="{{ followed }}" />

Moreover the changes of button style are controlled just applying different css classes, defined in the component, from component javascript side (using css the problem remains).

One thing i noted is: on iOS the the style is applied at each tap but seems like the component style is not refreshed! In fact scrolling it, hiding it, when reappearing it has the right style!!

Now I’m going to check your specific-iOS suggestion to see if it resolves in some way…


#5

If you don’t want to bind style properties, you can simply bind class property itself if that helps.


#6

I made a some trials with your ios-specific fix, directly in the real code. Sometimes it updates sometimes no. When it works there is some flickering on the listView item…

I found that probably the problem is related to this:


Still open after 2yrs :thinking:

and also this https://github.com/NativeScript/NativeScript/issues/4489

I’ll continue to investigate…


#7

@drmistral66 Did you find such flickering in my playground example, it was working perfectly for me - I tested with iOS 11.x in device.

You may give a try for RadListView once, I personally always prefer that over built-in ListView.


#8

Hi @manojdcoder, well, looking better it not a flickering but a kind of fading effect, not so bad but problem is that the component (that is a Button with some embedded data+style logic) needs to access to the list to do the trick, in my design the component does not know where it is placed, could be in a list item or in a page or somewhere else…

Anyway, I found that the fix described here seems working like a charm!
It is the only solution I found that leaves intact the app code without introduce tricks that break the philosophy of using components.

Just put this:

    Object.defineProperty(View.prototype, "isLayoutValid", {
        get: function () {
            return (this._privateFlags & PFLAG_LAYOUT_REQUIRED) !== PFLAG_LAYOUT_REQUIRED;
        },
        enumerable: true,
        configurable: true
    });   

in

node_modules/tns-core-modules/ui/core/view/view.ios.js

And everything is magically fixed!

I’m still testing at the moment but it seems really a bug, very important IMHO.
Anyway my question is: after 2 years, why has not been fixed yet? :thinking: