Changing an Elmish.WPF model from inside an async function - asynchronous

What is the accepted way in Elmish.WPF to have a Binding.cmd calling an async computation expression (CE) allow the delayed result of the async CE change the shared top-level model?
I want to do this without causing the UI thread to hang or starve (though having it somehow show busy is fine).
I tried having a part of the Model be mutable and mutating just that part of the record inside the async CE. This failed probably because the async CE is operating on its own copy of the Model.
Is there a way to pass a message with the delayed new value up to the top-level update function and update the global shared Model?
The functioning test code is in a repo here: make 'FandCo_SingleCounter` the Startup Project to run and test in VS2022
The important bits of my code is:
MainWindow.XAML fragment:
...begin of <Window>...
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,10,0,0">
<TextBlock Text="{Binding DISPLAY_state}" Width="110" Margin="0,5,10,5" />
<Button Command="{Binding CMD_get_state}" Content="DO IT!" Width="50" Margin="0,5,10,5" />
</StackPanel>
...to end of </Window>...
Program.fs fragment(s):
type Model =
{ mutable DISPLAY_state: string
}
type Msg =
| CMD_get_state
let init =
{ DISPLAY_state = "foo"
}
let ASYNC_get_state (m: Model) :Model =
async {
Console.WriteLine( "async 0: "
+ System.DateTime.Now.Millisecond.ToString()
+ " - "
+ m.DISPLAY_url_state)
m.DISPLAY_url_state <- "bar"
Console.WriteLine( "async +: "
+ System.DateTime.Now.Millisecond.ToString()
+ " - "
+ m.DISPLAY_state)
Threading.Thread.Sleep(5000)
Console.WriteLine( "async ++: "
+ System.DateTime.Now.Millisecond.ToString()
+ " - "
+ m.DISPLAY_state)
}
|> Async.StartImmediate
Console.WriteLine( "m.Display_url_state 0: "
+ System.DateTime.Now.Millisecond.ToString()
+ " - "
+ m.DISPLAY_state)
Console.WriteLine( "m.Display_state 1: "
+ System.DateTime.Now.Millisecond.ToString()
+ " - "
+ m.DISPLAY_state)
{ m with DISPLAY_state = "baz" }
let update msg m =
| CMD_get_state => ASYNC_get_state m
let bindings () : Binding<Model, Msg> list = [
"DISPLAY_url_state" |> Binding.oneWay (fun m -> m.DISPLAY_url_state)
"CMD_get_url" |> Binding.cmd CMD_get_url
]
...etc...to end of Elmish.WPF Core F# file.
The result of this is:
async 0: 275 - foo
async +: 591 - bar
async ++: 160 - True
m.Display_state 0: 164 - True
m.Display_state 1: 167 - True
[13:26:18 VRB] New message: CMD_get_state
Updated state:
{ DISPLAY_url_state = "baz" }
[13:26:18 VRB] [main] PropertyChanged DISPLAY_state
[13:26:18 VRB] [main] TryGetMember DISPLAY_state
At the end DISPLAY_state binding in the MainWindow.XAML updates to the value baz and not the desired value bar.
How is this supposed to be done?

I am the maintainer of Elmish.WPF.
Is there a way to pass a message with the delayed new value up to the top-level update function and update the global shared Model?
This is not exactly a question specific to Elmish.WPF in the sense that all derivates of Elmish (and in fact all MVU architectures) have to provide a way to appropriately execute async code that returns a message.
There are two ways to do this with Elimsh (and thus Elmish.WPF):
A subscription. See the SubModel sample and especially this line.
An (Elmish) command. See the FileDialogs sample and especially these lines.
The Elmish.WPF binding named cmd has nothing to do with this. This binding is named after the WPF interface ICommand.

Related

Robot Framework: Timed out waiting for page load

We have run our Robot Framework environment nearly one year without any problems, but now we get the error message:
TimeoutException: Message: Timed out waiting for page load.
Stacktrace:
at Utils.initWebLoadingListener/< (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver#googlecode.com/components/driver-component.js:9089)
at WebLoadingListener/e (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver#googlecode.com/components/driver-component.js:5145)
at WebLoadingListener/< (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver#googlecode.com/components/driver-component.js:5153)
at fxdriver.Timer.prototype.setTimeout/<.notify (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver#googlecode.com/components/driver-component.js:625)
What could be problem? I checked the disk space and there are disk space left.
A timeout error can have a laundry list of possible issues. Loading a page after a year of smooth operation narrows it down a little, but there are still many possibilities. Connection speeds sometimes change, sometimes the page you're loading up has added features that cause it to take longer to load or was just written poorly so it loads slowly... you get the idea. Without the code of the page or your code to look at, I can only suggest two fixes.
First, in the code of Selenium2Library, there is a timeout variable somewhere that can be set with Set Selenium Timeout. The default is 5 seconds, but if your page is taking longer to load, then increasing it might solve your problem. This assumes that your page loads at a reasonable rate in manual testing and that opening it is the least of your concerns.
Second, it's possible that you're testing an AngularJS application, not a normal website. If that's true, then you're going to want to use ExtendedSelenium2Library, not Selenium2Library. ExtendedSelenium2Library is better-equipped to deal with AngularJS applications and includes code to wait for Angular applications to load.
The old webdriver.xpi is buggy about page load handling. Timers are not correctly canceled, resulting in random windows switches and memory leaks. I copy here some replacement code that may be useful to anybody.
var WebLoadingListener = function(a, b, c, d) {
if ("none" == Utils.getPageLoadStrategy()) {
b(!1, !0);
} else {
this.logger = fxdriver.logging.getLogger("fxdriver.WebLoadingListener");
this.loadingListenerTimer = new fxdriver.Timer;
this.browser = a;
var self = this;
var e = function(a, c) {
self.destroy ();
b(a, c);
};
this.handler = buildHandler(a, e, d);
a.addProgressListener(this.handler);
-1 == c && (c = 18E5);
this.loadingListenerTimer.setTimeout(function() {
e(!0);
}, c);
WebLoadingListener.listeners [this.handler] = this;
goog.log.warning(this.logger, "WebLoadingListener created [" + Object.keys (WebLoadingListener.listeners).length + "] " + d.document.location);
}
};
WebLoadingListener.listeners = {};
WebLoadingListener.removeListener = function(a, b) {
if (b.constructor !== WebLoadingListener) {
b = WebLoadingListener.listeners [b];
}
b.destroy ();
};
WebLoadingListener.prototype.destroy = function() {
if (this.browser) {
this.loadingListenerTimer.cancel();
this.browser.removeProgressListener && this.handler && this.browser.removeProgressListener(this.handler);
delete WebLoadingListener.listeners [this.handler]
this.loadingListenerTimer = undefined;
this.browser = undefined;
goog.log.warning(this.logger, "WebLoadingListener destroyed [" + Object.keys (WebLoadingListener.listeners).length + "]");
}
};
enter code here

Printing the results from a select query with Genie

I have created the database in SQL lite and improved the little program to handle it (list, add, remove records). At this point I am trying to list the contents from the database using the prepared statement step() function. However, I can't iterate over the rows and columns on the database.
I suspect that the reason for that is that I am not handling the statement appropriately in this line:
stmt:Sqlite.Statement = null
If that is the case, how to pass the statement from the main (init) function to the children function?
This is the entire code so far:
// Trying to do a cookbook program
// raw_imput for Genie included, compile with valac --pkg sqlite3 cookbook.gs
[indent=4]
uses Sqlite
def raw_input (query:string = ""):string
stdout.printf ("%s", query)
return stdin.read_line ()
init
db : Sqlite.Database? = null
if (Sqlite.Database.open ("cookbook.db3", out db) != Sqlite.OK)
stderr.printf ("Error: %d: %s \n", db.errcode (), db.errmsg ())
Process.exit (-1)
loop:bool = true
while loop = true
print "==================================================="
print " RECIPE DATABASE "
print " 1 - Show All Recipes"
print " 2 - Search for a recipe"
print " 3 - Show a Recipe"
print " 4 - Delete a recipe"
print " 5 - Add a recipe"
print " 6 - Print a recipe"
print " 0 - Exit"
print "==================================================="
response:string = raw_input("Enter a selection -> ")
if response == "1" // Show All Recipes
PrintAllRecipes()
else if response is "2" // Search for a recipe
pass
else if response is "3" //Show a Recipe
pass
else if response is "4"//Delete a recipe
pass
else if response is "5" //Add a recipe
pass
else if response is "6" //Print a recipe
pass
else if response is "0" //Exit
print "Goodbye"
Process.exit (-1)
else
print "Unrecognized command. Try again."
def PrintAllRecipes ()
print "%-5s%-30s%-20s%-30s", "Item", "Name", "Serves", "Source"
print "--------------------------------------------------------------------------------------"
stmt:Sqlite.Statement = null
param_position:int = stmt.bind_parameter_index ("$UID")
//assert (param_position > 0)
stmt.bind_int (param_position, 1)
cols:int = stmt.column_count ()
while stmt.step () == Sqlite.ROW
for i:int = 0 to cols
i++
col_name:string = stmt.column_name (i)
val:string = stmt.column_text (i)
type_id:int = stmt.column_type (i)
stdout.printf ("column: %s\n", col_name)
stdout.printf ("value: %s\n", val)
stdout.printf ("type: %d\n", type_id)
/* while stmt.step () == Sqlite.ROW
col_item:string = stmt.column_name (1)
col_name:string = stmt.column_name (2)
col_serves:string = stmt.column_name (3)
col_source:string = stmt.column_name (4)
print "%-5s%-30s%-20s%-30s", col_item, col_name, col_serves, col_source */
Extra questions are:
Does the definitions of functions should come before or after init? I have noticed that they wouldn't be called if I left all of them after init. But by leaving raw_input in the beginning the error disappeared.
I was trying to define PrintAllRecipes() within a class, for didactic reasons. But I ended up making it "invisible" to the main routine.
Many thanks,
Yes, you need to assign a prepared statement, not null, to stmt. For example:
// Trying to do a cookbook program
// raw_input for Genie included, compile with
// valac --pkg sqlite3 --pkg gee-0.8 cookbook.gs
[indent=4]
uses Sqlite
init
db:Database
if (Database.open ("cookbook.db3", out db) != OK)
stderr.printf ("Error: %d: %s \n", db.errcode (), db.errmsg ())
Process.exit (-1)
while true
response:string = UserInterface.get_input_from_menu()
if response is "1" // Show All Recipes
PrintAllRecipes( db )
else if response is "2" // Search for a recipe
pass
else if response is "3" //Show a Recipe
pass
else if response is "4"//Delete a recipe
pass
else if response is "5" //Add a recipe
pass
else if response is "6" //Print a recipe
pass
else if response is "0" //Exit
print "Goodbye"
break
else
print "Unrecognized command. Try again."
namespace UserInterface
def get_input_from_menu():string
show_menu()
return raw_input("Enter a selection -> ")
def raw_input (query:string = ""):string
stdout.printf ("%s", query)
return stdin.read_line ()
def show_menu()
print """===================================================
RECIPE DATABASE
1 - Show All Recipes
2 - Search for a recipe
3 - Show a Recipe
4 - Delete a recipe
5 - Add a recipe
6 - Print a recipe
0 - Exit
==================================================="""
namespace PreparedStatements
def select_all( db:Database ):Statement
statement:Statement
db.prepare_v2( """
select name, servings as serves, source from Recipes
""", -1, out statement )
return statement
def PrintAllRecipes ( db:Database )
print "%-5s%-30s%-20s%-30s", "Item", "Name", "Serves", "Source"
print "--------------------------------------------------------------------------------------"
stmt:Statement = PreparedStatements.select_all( db )
cols:int = stmt.column_count ()
var row = new dict of string, string
item:int = 1
while stmt.step() == ROW
for i:int = 0 to (cols - 1)
row[ stmt.column_name( i ) ] = stmt.column_text( i )
stdout.printf( "%-5s", item.to_string( "%03i" ))
stdout.printf( "%-30s", row[ "name" ])
stdout.printf( "%-20s", row[ "serves" ])
stdout.printf( "%-30s\n", row[ "source" ])
item++
A few pointers
Generally you want to avoid assigning null. null is no value. For example a boolean can either be true or false and nothing else, but a variable that can have no value makes things more complicated.
a:bool? = null
if a == null
print "I'm a boolean variable, but I am neither true nor false???"
If you are looking to declare a variable in Genie before assigning a value, for example when calling a function with an out parameter, don't assign anything. I have changed db:Database to show this
Process.exit( -1 ) should probably be used sparingly and really only for error conditions that you want to signal to a calling command line script. I don't think a user selected exit from the program is such an error condition, so I have changed Process.exit( -1 ) to break for that
The definition of functions doesn't matter whether it is before or after init, I prefer to put them after so the first function that is called, i.e. init, is at the top and easy to read
A class is a data type and yes, it can have functions, but usually you need some data defined in the class and the function is written to act on that data. A function in a class is often called a 'method' and in the past with object oriented programming classes were defined to group methods together. These methods had no data to act on and are defined as 'static' methods. The modern practise is to mainly use static methods for creating more complex object constructors, look up 'factory' methods and creational design patterns. Instead to group functions, and other syntax, we use namespaces. I have used a couple of namespaces in the example. Usually a namespace is given its own file or files. If you are thinking of splitting your Genie project into more source files then take a look at https://wiki.gnome.org/Projects/Genie#A_Simple_Build_Script
A primary key should be internal to the database and would not be presented to a user, only a database administrator would be interested in such things. So I have changed 'item' in the output to be a count of the number of entries displayed
Genie and Vala bind the SQLite C interface. If you need more details on a particular function take a look at C-language Interface Specification for SQLite

How to get document _id from Meteor cursor?

I have rewritten this question as i now understand my problem a bit more. The answers below remain relevant.
I have the following query which returns a record.
Template.game.helpers({
Game: function () {
var myGame = Games.findOne(
{
game_minutes: {$gt: MinutesSinceMidnightNow},
court_id: court,
game_date: {$gt: lastMidnight}
},
{
sort: {game_minutes: 1}
}
); // find
console.log(myGame);
console.log(myGame._id);
return myGame;
} // game function
}); //template scoreboard.helpers
Meteor.startup(function () {
Meteor.call('removeGames', court, MinutesSinceMidnightNow);
for(var i=0;i<incomingGames.length;i++){
var game = incomingGames[i];
var gameTime = game.game_time;
if ( MinutesSinceMidnightGameTime(gameTime) > MinutesSinceMidnightNow ) {
console.log("game # " + i + ' game time ' + MinutesSinceMidnightGameTime(gameTime) + ' now' + ' ' + MinutesSinceMidnightNow);
Meteor.call('insertGame', game);
} // if
} // for
// game = Meteor.call("nextGame", MinutesSinceMidnightNow, court, lastMidnight);
console.log(MinutesSinceMidnightNow + ', ' + court + ', ' + lastMidnight);
}); // startup
The first console.log shows a game object which includes the _id property. The second console log throws an error. How can I get the _id value?
On thinking more about this, the code may actually work. Console log eventually displays nthe id number. The strange thing is the error occurs before the game inserts in server startup. I guess the client started before the server and then reactively aligned with the real data once the server started? This is hard to get my head around coming from traditional web development.
Here is the console output
undefined scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:118
Exception in template helper: TypeError: Cannot read property '_id' of undefined
at Object.Template.game.helpers.Game (http://localhost:3000/client/scoreboard/scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:122:19)
at http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:2693:16
at http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:1602:16
at Object.Spacebars.call (http://localhost:3000/packages/spacebars.js?3c496d2950151d744a8574297b46d2763a123bdf:169:18)
at Template.game.HTML.DIV.Spacebars.With.HTML.SPAN.class (http://localhost:3000/client/scoreboard/template.scoreboard.js?0ad2de4b00dfdc1e702345d82ba32c20d943ac63:16:22)
at null.<anonymous> (http://localhost:3000/packages/spacebars.js?3c496d2950151d744a8574297b46d2763a123bdf:261:18)
at http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:1795:16
at Object.Blaze._withCurrentView (http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:2029:12)
at viewAutorun (http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:1794:18)
at Tracker.Computation._compute (http://localhost:3000/packages/tracker.js?192a05cc46b867dadbe8bf90dd961f6f8fd1574f:288:36) debug.js:41
game # 0 game time 1395 now 549 scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:148
game # 1 game time 1110 now 549 scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:148
game # 2 game time 1185 now 549 scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:148
game # 3 game time 1260 now 549 scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:148
549, 1, Wed Oct 22 2014 00:00:00 GMT+0930 (CST) scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:157
Object {_id: "scYEdthygZFHgP2G9", court_id: 1, game_date: Wed Oct 22 2014 09:09:50 GMT+0930 (CST), court_name: "Court 1", game_time: "18:30"…} scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:118
scYEdthygZFHgP2G9
I cannot comment on the accepted answer, so I'll put the explaination as to why you see the log error here.
Your code runs just fine, the problem is (and reason for your log error) that you don't take into account that your collection of games isn't populated with any data yet. The first line in your log output reads:
undefined scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:118
which corresponds to
console.log(myGame);
The first time Meteor renders your templates, you simply don't have any data in the Games collection - it's on the wire on the way to your client. Meteor then automatically reruns your templates when data has arrived, explaining the subsequent console outputs.
So basically, the only thing that is wrong with your code at this moment, is the console log that tries to output the _id, since the during the first evaluation there is no game (thus you trying to access the property "_id" of the object "undefined" - the log error message). Remove that line and you should be ready to go!
If the parameter being passed to the function is an array, you can use Array.every. If it's a cursor, you'd need to fetch the results first.
UPDATE
I've just seen your comment. If you're looking for the first game after timenow, just do:
game = Games.findOne({game_minutes: {$gt: timenow}, [ANY OTHER FILTER]}, {sort: {game_minutes: 1}});
I've assumed the collection is called Games, and obviously you need to substitute in any other filter details to get the right set of games to look through, but it should work.
If you can access the game collection, I prefer adding selector and options to your query:
next_game = Games.find(
{
game_minutes: {$gt: timenow}
},
{
sort: {game_minutes: 1},
limit: 1
});
If not, fetch, filter, and then get the minimum one.
new_games = games.fetch().filter(function(game){
return game.game_minutes > timenow;
});
next_game = _.min(new_games, function(game){
return game.game_minutes;
});

Failure in executeAsync with SQLite

I've created this code, to send some insert statements to a SQLite DB:
new_db.executeAsync(stmts,stmts.length, {
handleResult: function(aResultSet) {
Firebug.Console.log("insert_data -> handleResult (" + aResultSet + ")");
},
handleError: function(aError) {
Firebug.Console.log("insert_data -> handleError (" + aError.result + "," + aError.message + ")");
},
handleCompletion: function(aReason) {
Firebug.Console.log("insert_data -> completed");
Firebug.Console.log(aReason);
}
});
In the output, I find:
insert_data -> completed
65535
I cannot figure what this 65535 means. This shouldn't be an error (otherwise I would have insert_data -> handleError), but why the returned value isn't zero? Is there a way to obtain a description of the code?
In any case, no value is being inserted by my statements, so it should be a failure error code.
Thanks,
Livio
I've found the explanation... the stmts array was empty (stmts.length=0). That's the meaning of this strange return code... that should be somehow documented, in my opinion.

Using Closure compiler with Underscore.js _.template

Is there any way to compile Underscore.js templates on the server and get the Closure compiler to work with the generated code?
The main problem is that _.template:
_.template = function(str, data) {
var c = _.templateSettings;
var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
'with(obj||{}){__p.push(\'' +
str.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(c.interpolate, function(match, code) {
return "'," + code.replace(/\\'/g, "'") + ",'";
})
.replace(c.evaluate || null, function(match, code) {
return "');" + code.replace(/\\'/g, "'")
.replace(/[\r\n\t]/g, ' ') + "__p.push('";
})
.replace(/\r/g, '\\r')
.replace(/\n/g, '\\n')
.replace(/\t/g, '\\t')
+ "');}return __p.join('');";
var func = new Function('obj', tmpl);
return data ? func(data) : func;
};
generates JavaScript with a with-statement in it. The two obvious routes are:
modify Underscore.js's _.template not to generate withs
coerce Closure into playing nice
Is the second option possible?
Generally, the JS engines perform better without "with", so if generating it without "with" is an option that is likely the best solution.
Otherwise your options depend on whether you are hoping to using Closure Compilers ADVANCED mode. In SIMPLE mode, the compiler won't rename your properties on the template, and will assume that any undeclared variable are globals. So as long are your template object isn't causing any local variables to be shadowed it might "just work".

Resources