# Catch args.data in Component on Tapped/Clicked

**URL:** <https://forums.fusetools.com/t/catch-args-data-in-component-on-tapped-clicked/4980>\
**Category:** General\
**Created:** [July 27, 2017, 12:39pm UTC](https://forums.fusetools.com/t/catch-args-data-in-component-on-tapped-clicked/4980 "2017-07-27T12:39:39Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![superpikar](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.fusetools.com/superpikar/32/442_2.png) [@superpikar](https://forums.fusetools.com/u/superpikar)\
**Post date:** [July 27, 2017, 12:39pm UTC](https://forums.fusetools.com/t/catch-args-data-in-component-on-tapped-clicked/4980/1 "2017-07-27T12:39:39Z")

</div>

Hello,

I have a question about catching args.data inside Component on Tapped/Clicked.

**Background:**

I want to show a list of news from Observable in `NewsItem` component. The `NewsItem` component compose of title, content, and share button. The `NewsItem` doesn’t have any properties.

If I click on the news wrapper then it executes `clickWrapper` function, and if I click on share news then it will execute `shareNews` function then get the title and content.  
However, when I log the output of those function, I always get an empty object.

**Screenshots**

 ![screenshots](https://image.ibb.co/idV7fQ/Capture.jpg)

**Output:**

Below is the output when I click the `NewsItem` component of “News 1”, and click the share button of “News 3”

```auto
[Viewport]: click wrapper
[Viewport]: {"title":"News Title 1","content":"This is content of news 1"}
[Viewport]: ------
[Viewport]: share news
[Viewport]: {}
[Viewport]: click wrapper
[Viewport]: {"title":"News Title 3","content":"This is content of news 3"}
[Viewport]: ------

```

**Question:**

How can I get the args.data of the component when I click the share button?

Is anyone know how to solve this problem?

**My Files**

MainView.ux

```auto
<App>
	<JavaScript>
		var Observable=require('FuseJS/Observable');
	    var news = Observable([]);
		news.replaceAll([
	        { title: 'News Title 1', content: 'This is content of news 1' },
	        { title: 'News Title 2' , content: 'This is content of news 2' },
	        { title: 'News Title 3' , content: 'This is content of news 3' },
	        { title: 'News Title 4', content: 'This is content of news 4' }]);

	    module.exports = {
	    	news: news
	    };
	</JavaScript>
	<StackPanel Margin="0,50">
		<Each Items="{news}">
			<NewsItem />  
		</Each>
	</StackPanel>
</App>

```

NewsItem.ux

```auto
<Panel ux:Class="NewsItem" Color="#eaeaea" Margin="10,5">
  <JavaScript>
    clickWrapper = (args) => {
      console.log('click wrapper', JSON.stringify(args.data));
      console.log('------');
    }
    openNews = (args) => {
      console.log('open news', JSON.stringify(args.data));
    }
    shareNews = (args) => {
      console.log('share news', JSON.stringify(args.data));
    }

    module.exports = {
      clickWrapper,
      openNews,
      shareNews
    }
  </JavaScript>
  <Tapped>
    <Callback Handler="{clickWrapper}"></Callback>
  </Tapped>
  <StackPanel Padding="10">
    <StackPanel>
      <Tapped>
        <Callback Handler="{openNews}"></Callback>
      </Tapped>
      <Text Value="{title}" />	  
      <Text Value="{content}" FontSize="14" />	
    </StackPanel>
    <Text TextAlignment="Right" FontSize="12" Color="Red" Value="Share">
      <Tapped>
        <Callback Handler="{shareNews}"></Callback>
      </Tapped>
    </Text>  
  </StackPanel>
</Panel>

```

---

<div class="post-metadata">

**Author:** ![Uldis](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.fusetools.com/uldis/32/657_2.png) [@Uldis](https://forums.fusetools.com/u/Uldis)\
**Post date:** [July 27, 2017, 2:02pm UTC](https://forums.fusetools.com/t/catch-args-data-in-component-on-tapped-clicked/4980/2 "2017-07-27T14:02:44Z")

</div>

So the root cause of the problem you’re describing stems from a simple fact: when you introduce a JavaScript viewmodel in the component, it overwrites whatever other implicit data context was there.

That results in an empty object in the callback, since your new viewmodel doesn’t really export any data - it only contains those callbacks you’ve defined.

There are several ways you can work around this issue.

Most obvious one: put the callbacks in the parent data context, right next to where you have the `news` list. You can still do `<Callback Handler="{...}" />` from inside the component, since Fuse looks up the tree to find the nearest place where that callback is implemented. Don’t forget to remove `<JavaScript>` tags from the component! Something like this:

```auto
<App>
    <JavaScript>
        var Observable=require('FuseJS/Observable');
        var news = Observable(
            { title: 'News Title 1', content: 'This is content of news 1' },
            { title: 'News Title 2' , content: 'This is content of news 2' },
            { title: 'News Title 3' , content: 'This is content of news 3' },
            { title: 'News Title 4', content: 'This is content of news 4' }
        );
        function globalCallback(args) {
            console.log("global: " + JSON.stringify(args));
        }

        module.exports = {
            news: news,
            globalCallback: globalCallback
        };
    </JavaScript>

    <StackPanel Margin="0,50">
        <Each Items="{news}">
            <NewsItem Height="56" />
        </Each>
    </StackPanel>

    <Panel ux:Class="NewsItem" Color="#eaeaea" Margin="10,5">
      <Clicked>
        <Callback Handler="{globalCallback}" />
      </Clicked>
      <Text Value="{title}" Alignment="Center" />
    </Panel>

</App>

```

Second, you could use `ux:Property` to pass the params as properties to the component, and have a local JavaScript viewmodel that `module.exports` a local version of the data, like so:

```auto
<App>
    <JavaScript>
        var Observable=require('FuseJS/Observable');
        var news = Observable(
            { title: 'News Title 1', content: 'This is content of news 1' },
            { title: 'News Title 2' , content: 'This is content of news 2' },
            { title: 'News Title 3' , content: 'This is content of news 3' },
            { title: 'News Title 4', content: 'This is content of news 4' }
        );

        module.exports = {
            news: news
        };
    </JavaScript>

    <StackPanel Margin="0,50">
        <Each Items="{news}">
            <NewsItem Height="56" Title="{title}" Content="{content}" />
        </Each>
    </StackPanel>

    <Panel ux:Class="NewsItem" Color="#eaeaea" Margin="10,5">
      <string ux:Property="Title" />
      <string ux:Property="Content" />
      <JavaScript>
      function localCallback(args) {
        console.log("local: " + JSON.stringify(args));
      }
      module.exports = {
        localCallback: localCallback,
        localTitle: this.Title,
        localContent: this.Content
      };
      </JavaScript>
      <Clicked>
        <Callback Handler="{localCallback}" />
      </Clicked>
      <Text Value="{localTitle}" Alignment="Center" />
    </Panel>

</App>

```

And third option would be to look into using [UserEvents](https://www.fusetools.com/docs/ux-markup/user-events).

Hope this helps!

---

<div class="post-metadata">

**Author:** ![superpikar](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.fusetools.com/superpikar/32/442_2.png) [@superpikar](https://forums.fusetools.com/u/superpikar)\
**Post date:** [July 27, 2017, 2:54pm UTC](https://forums.fusetools.com/t/catch-args-data-in-component-on-tapped-clicked/4980/3 "2017-07-27T14:54:47Z")

</div>

> So the root cause of the problem you’re describing stems from a simple fact: when you introduce a JavaScript viewmodel in the component, it overwrites whatever other implicit data context was there.
> 
> That results in an empty object in the callback, since your new viewmodel doesn’t really export any data - it only contains those callbacks you’ve defined.

Whoa! I just know it. Thank you @Uldis for the enlightenment 😃

Since I’m familiar with vuejs & angular, and my `NewsItem` component will be used in many pages with the same behaviour defined in the javascript (going to another route, save or remove from bookmark, share to social media, etc), so I will stick with solution no.2 passing the object as properties.

* * *

MainView.ux

```auto
<App>
	<JavaScript>
		var Observable=require('FuseJS/Observable');
	    var news = Observable([]);
		news.replaceAll([
	        { title: 'News Title 1', content: 'This is content of news 1' },
	        { title: 'News Title 2' , content: 'This is content of news 2' },
	        { title: 'News Title 3' , content: 'This is content of news 3' },
	        { title: 'News Title 4', content: 'This is content of news 4' }]);

	    module.exports = {
	    	news: news
	    };
	</JavaScript>
	<StackPanel Margin="0,50">
		<Each Items="{news}">
			<NewsItem Post="{}" />  
		</Each>
	</StackPanel>
</App>

```

NewsItem.ux

```auto
<Panel ux:Class="NewsItem" Color="#eaeaea" Margin="10,5">
  <object ux:Property="Post" />
  <JavaScript>
    var Observable = require('FuseJS/Observable');
    // initialize empty value first
    var post = Observable({
      title: '',
      content: '',
    });
    post.value = this.Post.value;

    openNews = (args) => {
      console.log('open news', JSON.stringify(post.value));
    }
    shareNews = (args) => {
      console.log('share news', JSON.stringify(post.value));
    }

    module.exports = {
      post,
      openNews,
      shareNews
    }
  </JavaScript>
  
  <StackPanel Padding="10">
    <StackPanel>
      <Tapped>
        <Callback Handler="{openNews}"></Callback>
      </Tapped>
      <Text Value="{post.title}" />	  
      <Text Value="{post.content}" FontSize="14" />	
    </StackPanel>
    <Text TextAlignment="Right" FontSize="12" Color="Red" Value="Share">
      <Tapped>
        <Callback Handler="{shareNews}"></Callback>
      </Tapped>
    </Text>  
  </StackPanel>
</Panel>

```

Output when click on content of News 2 and click on share button on News 3

```auto
[Viewport]: open news
[Viewport]: {"title":"News Title 2","content":"This is content of news 2"}
[Viewport]: share news
[Viewport]: {"title":"News Title 3","content":"This is content of news 3"}

```

Regards.

---

<div class="post-metadata">

**Author:** ![Uldis](https://yyz1.discourse-cdn.com/flex035/user_avatar/forums.fusetools.com/uldis/32/657_2.png) [@Uldis](https://forums.fusetools.com/u/Uldis)\
**Post date:** [July 27, 2017, 3:11pm UTC](https://forums.fusetools.com/t/catch-args-data-in-component-on-tapped-clicked/4980/4 "2017-07-27T15:11:37Z")

</div>

Great!

Only note that the properties are implicit derived Observables, so they get populated async. A general pattern we suggest to use inside components looks something like this:

```auto
var localTitle = this.Title.map(function(x) {
    return x;
});

```

You can, of course, use any other [reactive operator](https://www.fusetools.com/docs/fusejs/observable-api#reactive-operators).

Don’t access these observables imperatively. Doing `console.log(this.Title.value)` will result in an empty value, because it simply hasn’t arrived yet.
