How to prevent ngAfterViewInit() to get called before ngOninit completes execution - angular7

I have used angular materials for sorting a a table in angular 7 . So what is happening I am calling rest service from ngOnInit() method . Then in ngAfterViewInit I have am wrting the below code for sorting.
ngAfterViewInit() {
this.dataSource.sort = this.sort;
}
But what is happening is it is not waiting for the rest service to complete the execution and ngAfterViewInit is called before ngOnInit completes exceution.
For the above reason Sorting is not happening in Webpage where I am displaying the table.

Saroj, you can use setTimeOut for this. In your case if you provide more details we can do this in a different way.
ngAfterViewInit() {
setTimeout(() => {
this.dataSource.sort = this.sort;
}, 500);
}

Related

Electron: Can same channel name use for ipcMain.on and ipcMain.handle?

Can we register the same channel for ipcMain.on method and ipcMain.handle()?
For eg:
ipcMain.handle('test', async(event,args) => {
let result = await somePromise();
return result;
});
ipcMain.on('test', async(event,args) => {
event.returnValue = await somePromise();
});
Will the above code, give the error No handler register for 'test'? if ipcRenderer called this via invoke and sendSync in an order?
for eg:
ipcRenderer.invoke('test', data).then(result => {
console.log(result);
return result;
});
someFunction(data) {
return ipcRenderer.sendSync('test', data);
}
This is one of those things that you can easily test out.
Looking at their code for ipcMain.handle, they store the channel name in an _invokeHandlers map that seems isolated from the rest of the module (meaning from ipcMain.on).
In fact, ipcMain extends an EventEmitter, which is a Node class that maintains its own internal structure for managing events (This is the module where on and once are defined).
So you should be able to safely use both ipcMain.on("test", ...) and ipcMain.handle("test", ...) as long as you trigger them using the appropriate mechanism: send/sendSync corresponds with on/once and invoke corresponds with handle/handleOnce.

Making a Future block until it's done

Is it possible to block a function call that returns a future?
I was under the impression calling .then() does it, but that's not what I'm seeing in my output.
print("1");
HttpRequest.getString(url).then((json) {
print("2");
});
print("3");
What I'm seeing in my output is:
1
3
2
The getString method doesn't have an async that would allow me to await it and then executes asynchronously in any case.
static Future<String> getString(String url,
{bool withCredentials, void onProgress(ProgressEvent e)}) {
return request(url, withCredentials: withCredentials,
onProgress: onProgress).then((HttpRequest xhr) => xhr.responseText);
}
How do I make it blocking without placing an infinite while loop before step 3 waiting for step 2 to be completed (not that it would work anyways due to the single thread nature of Dart)?
The above HttpRequest loads a config.json file that determines how everything works in the app, if the request for a field in the config is done before the config.json file is done loading, it causes errors, so I need to wait until the file is done loading before I allow calling getters on the fields of the class or getters needs to wait for the once-off loading of the config.json file.
Update, this is what I eventually did to make it work after Günter suggested I use a Completer:
#Injectable()
class ConfigService {
Completer _api = new Completer();
Completer _version = new Completer();
ConfigService() {
String jsonURI =
"json/config-" + Uri.base.host.replaceAll("\.", "-") + ".json";
HttpRequest.getString(jsonURI).then((json) {
var config = JSON.decode(json);
this._api.complete(config["api"]);
this._version.complete(config["version"]);
});
}
Future<String> get api {
return this._api.future;
}
Future<String> get version {
return this._version.future;
}
}
And where I use the ConfigService:
#override
ngAfterContentInit() async {
var api = await config.api;
var version = await config.version;
print(api);
print(version);
}
Now I get blocking-like functionality without it actually blocking.
There is no way to block execution until asynchronous code completes. What you can do is to chain successive code so that it is not executed before the async code is completed.
One way to chain is then
print("1");
HttpRequest.getString(url) // async call that returns a `Future`
.then((json) { // uses the `Future` to chain `(json) { print("2"); }`
print("2");
});
print("3"); // not chained and therefore executed before the `Future` of `getString()` completes.
An async call is just scheduling code for later execution. It will be added to the event queue and when the tasks before it are processed it itself will be executed. After an async call is scheduled the sync code `print("3") is continued.
In your case HttpRequest.getString() schedules a call to your server and registers (json) { print("2") as callback to be called when the response from the server arrives. Further execution of the application doesn't stall until the response arrives and there is no way to make that happen. What instead happens is that sync code is continued to be executed (print("3")).
If your currently executed sync code reaches its end, then the next scheduled task is processed the same way.
then() schedules the code (json) { print("2"); } to be executed after getString() completed.
await
async and await just make async code look more like sync code but otherwise it is quite the same and will be translated under the hood to xxx.then((y) { ... }).
I'm not sure I understand what you're trying to achieve, but it looks to me you want to do this:
myFunction() async {
print("1");
final json = await HttpRequest.getString(url);
print("2");
print("3");
}
async statement is only needed in the consumer function. In other words, producer functions doesn't need to have async, they only need to return a Future.
you should be able to do this:
Future consumerFunc() async {
print("1");
var response = await HttpRequest.getString(url);
print("2");
print("3");
}
and it should result:
1
2
3
Note: await replaces then methods

Callback after .swap() not working - ASP.NET SPA w/sammy.js

I am building a Single Page Application using ASP.NET and sammy.js, where all views except for the Home/Index view are rendered as partial views so that sammy can swap out the content of the main body with the partial view that is returned.
I am using the example given here, and everything loads fine as expected.
Similar to the above example, in my Home/Index page I have reference to a script called routing.js, which wraps the sammy function call in order to parse the MVC route:
var Routing = function (appRoot, contentSelector, defaultRoute) {
function getUrlFromHash(hash) {
var url = hash.replace('#/', '');
if (url === appRoot)
url = defaultRoute;
return url;
}
return {
init: function () {
Sammy(contentSelector, function () {
this.get(/\#\/(.*)/, function (context) {
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
}).run('#/');
}
};
}
I need to call a callback function after the content swap has fully completed in order to implement further jQuery functionality on the newly rendered content. My dilemma is that no matter what option I try from the sammy.js docs, nothing seems to run the callback after the content has been swapped.
I have tried all of the following (all "valid" ways of passing a callback according to the sammy.js docs):
content.load(url).swap(pageLoadScripts(url));
content.load(url).swap().onComplete(pageLoadScripts(url));
content.load(url).swap().then(pageLoadScripts(url));
content.load(url).swap().next(pageLoadScripts(url));
content.load(url,pageLoadScripts(url)).swap();
and even
content.load(url).swap();
pageLoadScripts(url);
In every case the pageLoadScripts function fires off prior to the content being swapped. Any ideas or suggestions on what to do differently?
This is a bit of a hack, but it works.
Inside the Sammy initialization function, I added the following override to the swap function just before the override to the get function:
this.swap = function (content, callback) {
var context = this;
context.$element().html(content);
pageLoadScripts(hashedUrl);
};
FWIW, I still have not been able to get callback to be anything other than 'undefined', even in this override function.
Managed to get this working:
// override for callback after page load
this.swap = function(content, callback) {
this.$element().html(content);
if (callback) {
callback();
}
};
// users
this.get('/#/users', function(context) {
context.load('/users').swap(function() { replaceBindings(viewModel.users); });
});
I managed to get the callback param to NOT be 'undefined' by wrapping it in another function.

Waiting for Futures raised by other Futures

I'm using the Lawndart library to access browser data, and want to collect the results of a set of queries. Here's what I thought should work:
numberOfRecordsPerSection(callback) {
var map = new Map();
db_sections.keys().forEach((_key) {
db_sections.getByKey(_key).then((Map _section) {
int count = _section.length;
map[_key] = count;
});
}).then(callback(map));
}
However, when the callback is called, map is still empty (it gets populated correctly, but later, after all the Futures have completed). I assume the problem is that the Futures created by the getByKey() calls are not "captured by" the Futures created by the forEach() calls.
How can I correct my code to capture the result correctly?
the code from How do I do this jquery pattern in dart? looks very similar to yours
For each entry of _db.keys() a future is added to an array and then waited for all of them being finished by Future.wait()
Not sure if this code works (see comments on the answer on the linked question)
void fnA() {
fnB().then((_) {
// Here, all keys should have been loaded
});
}
Future fnB() {
return _db.open().then((_) {
List<Future> futures = [];
return _db.keys().forEach((String key_name) {
futures.add(_db.getByKey(key_name).then((String data) {
// do something with data
return data;
}));
}).then((_) => Future.wait(futures));
});
}

pass an errormessage from server to client

I defined some class to query a database.
class SqlGetData {
ConnectionPool pool;
List<String> rows;
SqlGetData(this.pool);
Future <List<String>> run(String sQuery) {
rows = new List<String>();
return readData(sQuery).then((_) {
return rows;
});
}
Future readData(String sQuery) {
return pool.query(sQuery).then((result) {
return result.forEach((row) {
String s = JSON.encode(row);
rows.add(s);
});
});
}
}
which I call like this:
var sql = new SqlGetData(pool);
sql.run('select firstName, lastName from person where id =' + s1).then((rows) {
some code here to process the data
});
If the database is not running I get an error on the return pool.query in readData, which I want to catch and pass to the client in some error message.
How and where can I code the try ... catch ... to prevent the server from dying? My problem is that I have to return futures, which is still difficult for me to grasp.
Take a look at this article Futures and Error Handling (if you haven't already).
There are two places:
.then((_) => doSomething(),
onError: (e) => doErrorHandling()).catchError((e) => doErrorHandling());
Guenter's answer is good. Here are a couple of extra tips.
It's more common to use .catchError() than the named parameter, if in doubt just use .catchError().
One problem with async code is if you forget to add a catchError handler anywhere in your codebase, and an error is triggered, it will bring your whole server down. Not good. However You can use Zones to handle uncaught errors in your code, and prevent this from happening.
There isn't much documentation about Zones at the time of writing, as it is a new feature. Florian Loitsch is working on an article which will appear here sometime soon. Here is an example of using runZoned():
runZoned(() {
var pool = new Pool.connect(...); // Don't know pool API, just making this up.
pool.query(sql).then((result) {
print(result);
});
// Oops developer forgot to add a .catchError() handler for the query.
// .catchError((e) => print('Query error: $e);
}, onError: (e) => print("Uncaught error: $e"));
This code will run without bringing down your server, despite the missing catchError() handler. Note, you will need to start the pool/connection within the same zone as the query is executed within.

Resources