How to format date with moment.js

I could not get moment.js to work. Below is my code. What am I missing?
<JavaScript>
const model = require("newsData");
	var moment = require("js/moment.js");
	module.exports = {
		news: model.getNews(),
            moment:moment,
			getNewsDetail: function(args){
			newsRouter.push("newsdetail", args.data)
		}
				
}

</JavaScript>
<DockPanel>

	<ScrollView LayoutMode="PreserveVisual">		
	<StackPanel ItemSpacing="20" Margin="10, 0, 10, 0">
			<Each Items="{news}">
						<StackPanel Padding="0, 10, 10, 10">
							<headerBg Alignment="Left" Padding="5,2,5,2" Margin="20,0,2,0" CornerRadius="2,2,2,2">
							<Text Value="moment('{thread.published}', 'YYYYMMDD').fromNow()" TextWrapping="Wrap" Alignment="TopLeft" FontSize="14" Color="#ffffff"/></headerBg>
						
					</StackPanel>
				
			</Each>
	</StackPanel>
	<Scrolled To="End" Within="300">
		</Scrolled>
</ScrollView>
	</DockPanel>
</EdgeNavigator>

Your code does not seem to be runnable as provided, so I’m not going to try to debug it. However, since I’ve recently used moment.js, here is a minimal example of using it. Make sure the moment.js file is in the js subdirectory from your project folder and that your projectname.unoproj file has something like "js/*.js:Bundle" or **.js:Bundle" so that Fuse will see the js file, e.g:

{
    "RootNamespace":"",
    "Packages": [
        "Fuse",
        "FuseJS"
    ],
    "Includes": [
        "*",
        "js/*.js:Bundle"
    ]
}

The MainView.ux below will display a text saying ‘in 2 years’

For more general understanding of how to use Fuse, see:

Here is the code:

<App>
	<ClientPanel>
        <ScrollView>
        	<Panel>
        		<JavaScript>
					var moment = require('js/moment');

					var fromNow = function() {
						var val = moment('20200220', 'YYYYMMDD').fromNow();
						console.log('val = ' + val);
						return val
					}

					module.exports= {
						fromNow: fromNow()
					}
        		</JavaScript>
        		<Text Value="{fromNow}"/>
        	</Panel>
        </ScrollView>
	</ClientPanel>
</App>

One more note. It seems you cannot call arbitrary functions with arguments like you are trying to do from ux markup.

For example the following works if you have dateStr exported in javascript:

<Text Value="Hello, {= toLower({dateStr})}!"/>

However, if you export some arbitrary function like fromNow, it doesn’t work anymore:

<Text Value="Hello, {= fromNow({dateStr})}!"/>

The supported functions are listed at the bottom of https://www.fusetools.com/docs/ux-markup/expressions

I think if you use observables together with putting all the business logic in js, hopefully you can achieve the effect you want.

Thanks for the reply, it was quite helpful. But the issue is, the date I am converting is not a numeric value as your example shows but a value from data coming from am API. How can I handle that? Kindly see code below as an example

var moment = require("js/moment.js");
var fromNow = function() {
   var val = moment("{thread_published}", 'YYYYMMDD').fromNow();
   console.log('val = ' + val);
   return val
}


	module.exports = {
		news: model.getNews(),
		fromNow: fromNow(),
			getNewsDetail: function(args){
			newsRouter.push("newsdetail", args.data)
		}
				
}

</JavaScript>

The data string I want to display in the text value is {thread_published}. At the moment it returns invalid date.

Hi,

In the code above I think you’re getting UX syntax (with the “{hello}” stuff) confused with javascript syntax. As far as I know, these are quite distinct things in Fuse. I don’t think you can use the “{hello}” syntax directly in your javascript business logic.

I’ll try to clarify with an example. Let’s say you’re getting the thread_published date from an asynchronous fetch request (maybe triggered by a button in the UI or something). You could bind that result to a Fuse javascript Observable object.

In your JS code something like this should work:

var moment = require("js/moment");

var Observable = require("FuseJS/Observable");

var thread_published_moment = Observable();

//https://developer.mozilla.org/en-US/docs/Web/API/Request
var url = 'http://your.service.com';
var request = new Request(url);
var response = fetch(request);

response.then(function(response) {
	responseJson = response.json();
	console.log("response = " + JSON.stringify(responseJson)); 
	return responseJson;
})
.then(function(jsonData) {
	console.log("jsonData = " + JSON.stringify(jsonData));
	var thread_published_string = jsonData.thread_published;

	//set the observable value
	var thread_published_moment.value = moment(thread_published_string); 

	return jsonData;
})
.catch(function(error) {
	console.log("error = " + error.message);
	
	return error.message;
});

// set up reactive functions so that any time thread_published_moment value changes, your UI will automatically update what is being displayed
var thread_published_as_string = thread_published_moment.map(function(m){return m.format('YYYY-MM-DD')});
var thread_published_from_now = thread_published_moment.map(function(m){return m.fromNow()});

modules.export = {
	thread_published_as_string: thread_published_as_string,
	thread_published_from_now: thread_published_from_now
};

Now in UX, you can display

<Text Value="{thread_published_as_string}"/>
<Text Value="{thread_published_from_now}"/>

This will automatically be updated each time your fetch request runs or any time you modify the value of the underlying thread_published_moment observable object.

Note: I’m not an expert in Fuse, so maybe there is a better way to get things exposed in a reactive way than the reactive functions I’ve written (https://www.fusetools.com/docs/fusejs/observable). I know in a future release they are planning to provide a component ‘state’ API that is supposed to be better, but I don’t know if there is a nicer way to do handle it right now.

The example code I’ve provided is not a complete runnable example as I don’t have time to put that together right now, but I hope it’s helpful…

Hello Vlad. The little issue I have with your solution is that I could not get it to work with my working App. I already have a running news app. But the example you gave does not seem to work with my code. could you please show me example code that will work with my code?

Hmm, well, assuming your last post had all the javascript that was relevant (the starting Javascript tag was clipped, so I don’t know what else was missing), you can make the following changes:

<Javascript>
	var moment = require("js/moment.js");
	var thread_published = Observable();
	// need get the date from somewhere like a local database or from the web...
	thread_published.value = get_thread_published_as_string(); 
	var fromNow = function() {
	   var val = thread_published.map(function(d) { return moment(d, 'YYYMMDD').fromNow()}); 

	   console.log('val = ' + val); //the observable that contains the value
	   console.log('val.value = ' + val.value); //the actual value

	   return val
	}

	module.exports = {
		news: model.getNews(),
		fromNow: fromNow(),
		getNewsDetail: function(args) {
			newsRouter.push("newsdetail", args.data)
		}
	}
</JavaScript>

In your UX file, you can use <Text Value="{fromNow}"/> and it will display the current value of thread_published using moment’s fromNow logic. Any time thread_published.value changes, this change will automatically be propagaged to what is displayed on the screen.

I hope I interpreted what you wanted correctly.

Hello Vlad, Thanks for the help. I have found a solution to it.