Skip to content
This repository was archived by the owner on Aug 7, 2021. It is now read-only.

WebPack: custom xml-component tap event does not work anymore when there is no code-behind file #865

Closed
tsonevn opened this issue Apr 16, 2019 · 3 comments
Assignees
Labels

Comments

@tsonevn
Copy link

tsonevn commented Apr 16, 2019

@felix-idf commented on Mon Apr 15 2019

Environment

  • CLI: 5.3.2
  • Cross-platform modules: 5.3.1
  • Android Runtime: 5.3.1
  • iOS Runtime: -
  • Plugin(s): -

Describe the bug
In our app, we want to share some xml-snippets between several pages, but only the UI part.

//./shared/my-component.xml
<StackLayout backgroundColor="yellow" padding="10">
    <Button text="Button 1" tap="customTapEvent1"/>
    <Button text="Button 2" tap="customTapEvent2"/>
</StackLayout>
//./main-page.xml
<Page xmlns:shared="shared" navigatingTo="onNavigatingTo">
    <!--  ...  -->
    <StackLayout>
        <shared:my-component/>
    </StackLayout>
</Page>
//./main-page.js
exports.customTapEvent1 = function (args) {
    alert("customTapEvent1");
};


exports.customTapEvent2 = function (args) {
    alert("customTapEvent2");
};

So there is no code-behind file for the my-component.xml.
We only want to shre the UI part and the tap events of the buttons should differ from page to page.

When running the app with tns run android, everything works as expected.
But when running the app using tns run android --bundle, the tap event is not raised at all.

I know, that this would work by adding a my-component.js file and moving those tap events to that file, but we really want to share only the UI part, so this is no solution for us.

Sample project
For an unknown reason, I am not able to paste my zipped sample project here, I will try to do that in the comments.


@felix-idf commented on Mon Apr 15 2019

Here is the complete sample project
WebPackIssue.zip

@rosen-vladimirov
Copy link
Contributor

Hey @felix-idf ,

Please excuse me for the so delayed reply. There's a difference in the way the context is applied when using the legacy and the bundle workflow. In order to make it work consistently, we recommend using the binding context. I.e.:

  1. Change the code in my-component.xml to:
<StackLayout backgroundColor="yellow" padding="10">
    <Button text="Button 1" tap="{{ customTapEvent1 }}"/>
    <Button text="Button 2" tap="{{ customTapEvent2 }}"/>
</StackLayout>
  1. Move the methods to createViewModel method of main-view-model.js
function createViewModel() {
    const viewModel = new Observable();
    viewModel.counter = 42;
    viewModel.message = getMessage(viewModel.counter);

    viewModel.onTap = () => {
        viewModel.counter--;
        viewModel.set("message", getMessage(viewModel.counter));
    };

    viewModel.customTapEvent1 = function (args) {
        alert("customTapEvent1");
    };

    viewModel.customTapEvent2 = function (args) {
        alert("customTapEvent2");
    };

    return viewModel;
}

Can you please give it a try and see if this solution is applicable for your case?

@NathanaelA
Copy link

@rosen-vladimirov - I don't know if it will solve his issue; but for me -- this is not imho a solution but a silly work-around.

I shouldn't have to use bindings to get the events on the page to work. In fact their are many screens I don't have anything bound. So, this basically creates more work, complicates the code a bit and means I have to create a separate class to put these functions in when they should live right where I initially put them.

@vakrilov
Copy link
Contributor

After more investigation - here is what I found.
The problem occurs when having an xml-only custom component.

In non-bundle workflow: The custom component "inherits" its context (the module with the code and event implementation - in our case main-page.js) from the page it was used.

In bundle workflow: We try to do the same with the following code in the builder. We check if there is registered module for the custom component. If there is such module - we load it and use it as a context of the xml file. If there is no such module - we do the context inheritance.

Looks like the problem is caused by the xml-namespace-loader.js, which registers both {moduleName} and {moduleName.}xml to point to the xml file. So in the repro-project the XML file is used as its own context which is definitely a bug as it cannot implement callbacks (the module just contains the string with the xml). Because the global.moduleExists(moduleName) check is true we never fallback to inheriting the context form the page and so the events are not fired.

We will do some checks to see if registering the xml file as a module is not needed in other cases. If that is not the case we can safely remove this line and match the behavior in bundle and non-bundle workflows.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants