This question is locked. New answers and comments are not allowed.
I'm experimenting on how I can restructure my NativeScript app using typescript. The first version of the application used the observable object as it is and everything was working fine. I tried restructuring the code by moving the view model to a different class that wraps around the observable object. The thing is that values are set just fine from the UI but it appears setting the value from code does not change the UI. The idea is to encapsulate everything in the view model and use the generated object like any javascript object without using .get and .set.
MainViewModel.ts
Main.ts
Main.xml
When the add function is called after a button is clicked, the list of items increase but the textbox is not cleared when I set that task property to an empty string.
I did try simply inheriting from observable instead of having a local copy but that caused the application to hang anytime I run it. Very sure I did not implement it well.
What do I do to get the two way binding to work? Am I approaching this wrongly? If so, what is the right way to go around this?
MainViewModel.ts
import observableModule = require(
"data/observable"
);
import observableArrayModule = require(
"data/observable-array"
);
import Utils = require(
"../lib/Utils"
);
export interface ITask { name: string; }
export class ViewModel {
private observable =
new
observableModule.Observable();
constructor(json?: any) {
this
.init();
if
(json)
for
(
var
key
in
json)
this
.observable.set(key, json[key]);
}
private init() {
this
.observable.set(
'task'
,
''
);
this
.observable.set(
'tasks'
,
new
observableArrayModule.ObservableArray());
}
public textFieldId = Utils.uniqueId(
"ui"
);
public get task(): string {
return
this
.observable.get(
'task'
);
}
public set task(value) {
this
.observable.set(
'task'
, value);
}
public get tasks(): observableArrayModule.ObservableArray<ITask> {
return
this
.observable.get(
'tasks'
);
}
public set tasks(value) {
this
.observable.set(
'tasks'
, value);
}
public addTask(task: ITask) {
this
.tasks.push(task);
}
}
Main.ts
import viewModule = require(
"ui/core/view"
);
import textFieldModule = require(
"ui/text-field"
);
import pageModule = require(
"ui/page"
);
import frame = require(
"ui/frame"
);
import model = require(
"./mainViewModel"
);
var
page: pageModule.Page;
var
vm =
new
model.ViewModel();
export
function
onPageLoaded(args) {
page = args.object;
page.bindingContext = vm;
if
(frame.topmost().android) {
frame.topmost().android.actionBar.hide();
}
}
export
function
add() {
vm.tasks.push({ name: vm.task });
vm.task =
""
;
var
view = viewModule.getViewById<textFieldModule.TextField>(page, vm.textFieldId);
view.dismissSoftInput();
}
Main.xml
<
Page
loaded
=
"onPageLoaded"
>
<
GridLayout
rows
=
"auto,*"
>
<
StackLayout
orientation
=
"horizontal"
row
=
"0"
>
<
TextField
width
=
"200"
text
=
"{{task}}"
hint
=
"Enter a task"
id
=
"{{textFieldId}}"
/>
<
Button
text
=
"Add"
tap
=
"add"
></
Button
>
</
StackLayout
>
<
ListView
items
=
"{{tasks}}"
row
=
"1"
>
<
ListView.itemTemplate
>
<
Label
text
=
"{{name}}"
/>
</
ListView.itemTemplate
>
</
ListView
>
</
GridLayout
>
</
Page
>
When the add function is called after a button is clicked, the list of items increase but the textbox is not cleared when I set that task property to an empty string.
I did try simply inheriting from observable instead of having a local copy but that caused the application to hang anytime I run it. Very sure I did not implement it well.
What do I do to get the two way binding to work? Am I approaching this wrongly? If so, what is the right way to go around this?