console.log not working inside a nativescript view model function - nativescript

I am very new to nativescript. I have tried to debug a sample app through the console.log. It's a view model page code
var Observable = require("data/observable").Observable;
console.log(1);
function getMessage(counter) {
if (counter <= 0) {
return "Hoorraaay! You unlocked the NativeScript clicker achievement!";
} else {
return counter + " taps left";
}
}
function createViewModel() {
console.log(2);
var viewModel = new Observable();
viewModel.counter = 42;
viewModel.message = getMessage(viewModel.counter);
viewModel.onTap = function() {
this.counter--;
this.set("message", getMessage(this.counter));
}
return viewModel;
}
exports.createViewModel = createViewModel;
The first log is appearing. But not the log 2. But I think the createViewModel method is being called.
I am using this command to execute my app already opened in genemotion
tns livesync android --watch --debug
Nor
tns emulate android
works.
Thanks in advance

The second log statement is inside a function. It will be executed when that function is executed. Somewhere you need to execute createViewModel()

Related

Dart component progress bar only updating at the end of loop

I'm developing an app in angular dart and trying to animate a progress bar which shows progress of a file upload. I'm simply parsing the JSON from the file, and sending them off to a service with a _service.create(....) method.
I've put all of this code in an async method which is called when my submit button is clicked:
void uploadFile() async {
submitButton.attributes.addAll({ 'disabled': '' });
progress.value = 0;
FileList files = input.files;
if (files.isEmpty) {
_handleError("No file selected");
//handle error, probably a banner
return;
}
File file = files.item(0);
FileReader reader = new FileReader();
//reader.result
reader.onLoadEnd.listen((e) async {
Map map = json.decode(reader.result);
var combinations = map['combinations'];
progress.max = combinations.length;
int loopCount = 0;
combinations.forEach((e) async {
await _service.create(VJCombination.fromJSON(e)).then((_) {
combinationCount++;
progress.value++;
loopCount++;
if (loopCount == combinations.length) {
submitButton.attributes.remove('disabled');
}
});
});
isLoadSuccessful = true;
});
reader.onError.listen((evt) => print(evt));
reader.readAsText(file);
progress.value = 10;
}
I'm getting the progress and the submitButton elements with the #ViewChild annotations:
#ViewChild('progress')
ProgressElement progress;
#ViewChild('submit')
ButtonElement submitButton;
The code works. The progress bar starts off empty, and after the file is read and the service gets the data, the progress bar is full.
My issue is that the UI is only updated after all of the combinations have been sent to the _service. So it seemingly goes from empty to full in one frame.
This code
combinations.forEach((e) async {
does not make sense, because forEach does not care about the returned Future
Rather use
for(var e in combinations) {
Not sure if this fixes your problem, but such code definitely needs to be changed.

How Clear Back Stack on Xamarin IOS?

When a user authenticates correctly, it will be directed to the HomeViewModel. I want to remove the possibility that it can return to the login screen so I have created a Custom Presenter to remove all the screens that are below the new screen.
The implementation is as follows:
public class CustomPresenter: MvxFormsIosPagePresenter
{
public CustomPresenter(UIWindow window, MvxFormsApplication mvxFormsApp)
: base(window, mvxFormsApp)
{
}
public override void Show(MvxViewModelRequest request)
{
if (request.PresentationValues?["NavigationCommand"] == "StackClear")
{
var navigation = FormsApplication.MainPage.Navigation;
Debug.WriteLine("Navigation Back Stack Count -> " + navigation.NavigationStack.Count());
navigation.PopToRootAsync();
Debug.WriteLine("Navigation Back Stack Count After PopToRootAsync -> " + navigation.NavigationStack.Count());
return;
}
base.Show(request);
}
}
When the authentication process finishes correctly, I navigate to the home screen by passing a bundle with this special command:
LoginWithFacebookCommand.Subscribe(token => {
Debug.WriteLine("JWT Token -> " + token);
_userDialogs.ShowSuccess(AppResources.Login_Success);
var mvxBundle = new MvxBundle(new Dictionary<string, string> { { "NavigationCommand", "StackClear" } });
ShowViewModel<HomeViewModel>(presentationBundle: mvxBundle);
});
The problem is that it does not change the screen, it stays in the current one. What would be the way to do it correctly ?.
I am using MvvmCross 5.1.1 and MvvmCross.Forms 5.1.1
Thank you very much in advance.
As I understand it, PopToRootAsync() pops everything off the stack to the root. Which means you should then push your view that you wish to navigate to, onto your stack after that method is called i.e. use PushViewController(yourViewController) afterwards. Also, you should be using the new IMvxNavigationService by MvvmCross. You can give this a try:
var navigationService = Mvx.Resolve<IMvxNavigationService>();
LoginWithFacebookCommand.Subscribe(async (token) => {
Debug.WriteLine("JWT Token -> " + token);
_userDialogs.ShowSuccess(AppResources.Login_Success);
await navigationService.Navigate<HomeViewModel>();
});
To clear the backstack you basically need to override the Show method in the presenter and check whether your viewmodel is being called. If it is then set a new array of viewControllers. (Credit to #pnavk!!)
public class CustomPresenter : MvxIosViewPresenter
{
public override void Show(IMvxIosView view, MvxViewModelRequest request)
{
if (MasterNavigationController != null && view.ViewModel.GetType() == typeof(HomeViewModel))
{
var viewController = view as UIViewController;
MasterNavigationController.SetViewControllers(new UIViewController[] { viewController }, true);
}
else
base.Show(view, request);
}
}
Try this:
navigation.SetViewControllers(new UIViewController[] { vc }, true);
vc is the ViewController you want to set as the root of the navigation stack. You will need to get a reference to it which you can using the ViewControllers property on the NavigationController.
true - means you want to animate.

Fiiling the compose message at opening

I'm desesperatly seeking for a way to fill in the compose message when it opens, in a boostraped (restartless) TB add-on.
This is something that I did in my non-bootstraped add-on RemindIt
Thanks to Superjos I was able to manage the different listeners, and get the compose message filled with my custom message when it opened.
But... this works only for new (non recycled) windows. If I close a compose window, then click on "new message", it is recycled (I guess) and the "load" event is not fired.
I tried different tricks (see for example onComposeInit2), but at the end, I'm not able to alter compose message for non new windows, even if it looks like my addon is calling the editing method (this is what one can see in the log).
Any ideas ?
See my test/bootstrap.js code :
function log(s){
Components.classes["#mozilla.org/consoleservice;1"]
.getService(Components.interfaces.nsIConsoleService).logStringMessage("test: "+s);
}
// Thanks (a lot ! ) to Superjos :
// https://stackoverflow.com/questions/25989864/get-sender-and-recipients-in-thunderbird-extension-upon-sending-message
var winListener={
onOpenWindow: function(win){
compose=win.docShell.
QueryInterface(Components.interfaces.nsIInterfaceRequestor).
getInterface(Components.interfaces.nsIDOMWindow);
compose.addEventListener('compose-window-init', winListener.onComposeInit, true);
},
onComposeInit: function(event){
var document=event.currentTarget.document;
var edit=document.getElementById("content-frame");
edit.addEventListener("load",winListener.onComposeLoad,true);
log("compose init "+event.currentTarget);
event.currentTarget.removeEventListener(event.type,winListener.onComposeInit , true);
},
onComposeLoad: function(event){
var edit=event.currentTarget;
var editor=edit.getHTMLEditor(edit.contentWindow);
log("compose load");
winListener.alterMessage(editor);
},
alterMessage: function(editor){
var msg="Hello<br>";
editor.insertHTML(msg);
log("alter message "+editor);
},
onComposeInit2: function(event){
var document=event.currentTarget.document;
var edit=document.getElementById("content-frame");
edit.addEventListener("load",winListener.onComposeLoad,true);
log("compose init "+event.currentTarget);
var editor=edit.getHTMLEditor(edit.contentWindow);
if( editor!=null ){
// the editor is ready, remove load event listener
edit.removeEventListener("load",winListener.onComposeLoad,true);
// and call the method to alter message
winListener.alterMessage(editor);
}
//edit.addEventListener("focus",winListener.onFocus,true);
event.currentTarget.removeEventListener(event.type,winListener.onComposeInit2 , true);
},
/*
onFocus: function(event){
event.currentTarget.removeEventListener("focus",winListener.onFocus,true);
var edit=event.currentTarget;
var editor=edit.getHTMLEditor(edit.contentWindow);
winListener.alterMessage(editor);
log("focus");
},
onComposeClose: function(event){
var document=event.currentTarget.document;
var edit=document.getElementById("content-frame");
edit.addEventListener("focus",winListener.onFocus,true);
log("close");
}
*/
}
function startup(aData, aReason) {
log("startup");
var windowMediator = Components.classes['#mozilla.org/appshell/window-mediator;1'].
getService(Components.interfaces.nsIWindowMediator);
windowMediator.addListener(winListener);
}
function shutdown(aData, aReason) {
log("shutdown");
var windowMediator = Components.classes['#mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator);
windowMediator.removeListener(winListener);
}
function install(aData, aReason) {
log("install");
}
function uninstall(aData, aReason) {
log("uninstall");
}
I found the solution from this http://forums.mozillazine.org/viewtopic.php?f=19&t=450474
There is a compose-window-reopen event that is fired when the window is reopen.

Why does this Ti.UI.WebView.fireEvent() call throw an exception when a listener is present?

I create a new window with
var win = Ti.UI.createWindow({url:'page.js'});
win.listeners = {
'type': function(e){ alert('test'); }
}
win.open();
Inside page.js, I add the specified listeners to a Ti.UI.WebView inside the window.
for (var type in win.listeners) {
Ti.API.info(win.listeners[type])
webView.addEventListener(type, win.listeners[type]);
}
Ti.API.info(win.listeners['type']) prints the function as "<KrollCallback: 0xb272160>"
A call to webView.fireEvent('type') executes fine if there are no listeners. But if I add listeners to the webView as above, the call to fireEvent throws an exception.
What is KrollCallback and why does fireEvent crash if there are listeners present?
The problem is that using url:'page.js' with createWindow() starts a new context. This type of setup will work if page.js is like this:
exports.getWindow(config) {
var webView = Ti.UI.createWebView({});
for (var type in config.listeners) {
webView.addEventListener(type, config.listeners[type]);
}
}
Then, use the window like this:
var win = require('page').getWindow({
listeners = {
'event_type': function(e){ alert('event_type test'); }
}
});
win.open();

Cannot update label on Google Apps Script GUI Builder Interface at runtime

I have an interface that calls a script for spreadsheet creation using data taken from other spreadsheet. I want the interface to update its labels at runtime in order to give visual feedback to the user and let him know the script is running and it's not stuck. When I try to update the label I put in the interface, it doesn't update the first time, but updates correctly after myFunction() reaches its end. Which means I can see the message "Creation Completed", but the message "Creating file..." is never shown. Also, the button buttonCompile is never disabled so it seems that the instructions before myFunction() are not executed at all. How can I get the labels updated and the button disabled before myFunction() starts executing? (I already double-checked variable references)
function doGet() {
var app = UiApp.createApplication();
app.add(app.loadComponent("File creation"));
var buttonCreate = app.getElementById('createBtn');
var handlerCrea = app.createServerHandler('createClickHandler');
buttonCreate.addClickHandler(handlerCreate);
return app;
}
function createClickHandler(e) {
var app = UiApp.getActiveApplication();
var label = app.getElementById('createLbl');
label.setText("Creating file...");
var buttonCompile = app.getElementById('compileBtn');
buttonCompile.setEnabled(false);
myFunction();
label.setText("Creation completed.");
buttonCompile.setEnabled(true);
app.close();
return app;
}
The cause of this behavior is that the GUI is updated only after leaving a handler. A workaround is to use two handlers. The 1st one sets the label text to Creating file... and disables the button, the 2nd one executes the myFunction function, changes the text to Creation completed, and eanbles the button. Here is an example. It disables/enables the button and the worker handler simply waits 5 seconds.
function doGet(e) {
var app = UiApp.createApplication();
var container = app.createHorizontalPanel().setId('container');
var btnPerformance = app.createButton("Performance Demo").setId('btnPerformance');
var handlerPerformance = app.createServerHandler('onBtnPerformanceClick');
var handlerWait = app.createServerHandler('onWait');
btnPerformance.addClickHandler(handlerPerformance);
btnPerformance.addClickHandler(handlerWait);
container.add(btnPerformance);
app.add(container);
return app;
}
function enableControls(enable) {
var lstControls = [ 'btnPerformance' ];
var app = UiApp.getActiveApplication();
for (var i = 0; i < lstControls.length; i++) {
var ctl = app.getElementById(lstControls[i]);
ctl.setEnabled(enable);
}
}
function onWait(e) {
enableControls(false);
return UiApp.getActiveApplication();
}
function onBtnPerformanceClick(e) {
Utilities.sleep(5000);
enableControls(true);
return UiApp.getActiveApplication();
}

Resources