Concatenate in XML


#1

Hello,

I would like to know if there is a simple way (other than using FormattedString) to concatenate a dynamic and a static value in a XML.

For example something like this (this is just an example of course):

<Label text="{{ value + 'sample text' }}" />
The above code will display “undefinedsampletext”

<Label text="{{ value }}" />
The above code will display the proper value (which would be set in the js file)

I don’t understand why the value becomes undefined when trying to concatenate (probably the wrong way ?).

PS: Not using angular
Nativescript 3.3.1 (also tried 3.4.0).
Testing on android

Thanks


#2

I suspect you declare your value as a property inside observable which usually fails in this case.

import { Observable } from 'data/observable';

export class HomeViewModel extends Observable {
    value:string = "Hello";
    constructor() {
        super();
    }
}

You have to use set method to add properties to observable. For example,

import { Observable } from 'data/observable';

export class HomeViewModel extends Observable {
    constructor() {
        super();
        this.set('value', 'Hello');
    }
}

#3

Here’s a simple example in playground, using the default JS files. Your code works as you entered it. There might be something else causes the issue.


#4

Hello,

Ty for your answers, it helped me pinpointing the following :
I was setting the value like this in the .js file

var pageData = new observableModule.fromObject({});

exports.pageLoaded = function(args) {
    page = args.object;
    page.bindingContext = pageData;
    pageData.set("value", "sometext");
};

.xml
<Label fontSize="42" text="{{ value + 'test' }}"></Label>

The above shows undefinedtest.

Doing this as in pentool example indeed works as intended however (sometexttest) :

var pageData = new observableModule.fromObject({
    "value":"sometext"
});

Not using fromObject and doing new Observable() is working aswell.
Displaying the value in the xml without concatenating anything like so
<Label fontSize="42" text="{{ fsz }}"></Label>
results in the initial code working.

I tried going into observable.js in tns-core-modules and using console.log it appears that no get functions are called when setting the value like in the initial code and concatenating it in the xml.

To sum this up :
ObservableFromObject.prototype.get is called when there is no concat whether setting the value when calling fromObject or using the set method.
Object.defineProperty get is called when concatenating and setting the value directly when calling fromObject
No get function is called when concatenating and setting the value using the set method resulting in undefined value except if not using fromObject

Did I miss something ? Also is fromObject supposed to always be used instead new Observable() now ?

Thanks


#5

There are two ways of doing it. In both cases, the XML file is the same, as in:

<Page loaded="onLoaded">
	<StackLayout verticalAlignment="center" class="text-center">
		<Label text="{{ 'Message is: ' + text }}" />
	</StackLayout>
</Page>

JS file - Option 1:

const Observable = require("data/observable");

var data = new Observable.Observable();

exports.onLoaded = function(args) {
	let page = args.object;

	page.bindingContext = data;
	data.set("text", "Hello World");
}

However, when using new Observable() the API points out, that in v3.x this is deprecated and you should be using new Observable.fromObject({ }).

URL REFs:
Check the ‘constructor’ box on this page: https://docs.nativescript.org/api-reference/classes/data_observable.observable)

or this github page: https://github.com/NativeScript/NativeScript/issues/4009

JS file - Option 2:

const Observable = require("data/observable");

var data = new Observable.fromObject({
	text: ""
});

exports.onLoaded = function(args) {
	let page = args.object;

	page.bindingContext = data;
	data.set("text", "Hello World");
}

Note, that if you remove the default value text: "", and just provide an empty object, it will not work and you will get Message is: undefined. So you should provide default values.

var data = new Observable.fromObject({ });

#6

Thank you for the explanation, but what is bothering me is why is there is a different behavior when wanting to concatenate ?
I mean, considering the JS file - Options 2 example, is this intended that you need to initialize “text” ONLY if you want to concatenate ? If you don’t and just display the value it works without it.