I have a zone related problem, and i can't get it working. i'm new to angular but have some basic javascript understanding.
So what is the problem, i can not get the view updated.
Im using a third party library for ionic BLE, and use this in a provider
providers/communication-controller.ts
set_ble_tolisten(){
//subscribe to receive notification, rx channel
console.log(' set_ble_tolisten' + NgZone.isInAngularZone());
this.ble.startNotification(this.peripheral_object.id,
this.TRANSPARANT_SERVICE, this.TX_CHARACTERISTIC).subscribe(
(data) => this.handlereceiveddata(data),
() => console.log('Unexpected Error', 'Failed to subscribe for
temperature changes')
)
}
ble_communication_controller(port,command,payload,payloadsize,
callback)
{
//create buffer
var BLE_Sendbuffer= new Int8Array(payloadsize+10);
var package_index = 0;
this.generatePacketID();
this.ble_send_que.push({
"packetid" : this.packetid,
"action" : callback
});
//Generate send message
BLE_Sendbuffer[ some data]
//send message
this.ble.write(this.peripheral_object.id,this.TRANSPARANT_SERVICE,
this.RX_CHARACTERISTIC,BLE_Sendbuffer.buffer).then(
() => console.log('ble message send'),
e => console.log('ble oops')
);
}
handlereceiveddata(buffer:ArrayBuffer){
var int8View = new Int8Array(buffer);
var ReceivedPacketID = 0;
console.log('handlereceiveddata ' + NgZone.isInAngularZone());
//first check the header
if( ((int8View[0] * 0x100) + int8View[1]) === this.HEADER)
{
//retrieve packetid from received packet
ReceivedPacketID = ((int8View[2] * 0x100) + int8View[3]);
if(ReceivedPacketID === 0) {
console.log('orgin io or rs232');
} else {
//find function based on packetid, and execute
let index_findresult = this.ble_send_que.findIndex(value =>
value.packetid === ReceivedPacketID);
if(index_findresult != -1)
{
this.ble_send_que[index_findresult].action(int8View);
}
//remove object from array
this.ble_send_que.splice(index_findresult, 1);
}
}
set_ble_tolisten() is called to subcribe on the promise.When data is received handlereceiveddata() is called.
To transmit data ble_communication_controller() is called, this function accepts a callback, which is stored. When the ble device response, the handlereceivedata() is called. This then call the callback which is stored a the ble_communication_controller() call
I created a page, configuration, this contains a ts a html and scss file
the configuration.ts
ionViewDidEnter() {
this.communicationController.set_ble_tolisten();
this.sync_device_gui('IO-1');
}
sync_device_gui(port){
console.log('call in zone ' + NgZone.isInAngularZone());
var io_port = 0;
if(port === ‘IO-1')
{
io_port = 0x05;
}
if(port === 'IO-2')
{
io_port = 0x06;
}
this.communicationController.ble_communication_controller(io_port,
GET_IO_STATE,0x00,0,this.update_state_gui);
}
update_state_gui(data){
//rule below added as explained in first comment (location ngzone.run).
this.zone.run(() => {
console.log('repsonse in zone ' + NgZone.isInAngularZone());
console.log('io port state ' + data);
console.log('repsonse in zone ' + NgZone.isInAngularZone());
if(data[8] == 0){
this.relay_1_toggle = true;
this.relay_2_toggle = true;
console.log('state is false set :'+ this.relay_1_toggle + '
state :' + this.relay_2_toggle );
}
if(data[8] == 1){
this.relay_1_toggle = false;
this.relay_2_toggle = false;
console.log('state is true set :'+ this.relay_1_toggle + '
state :' + this.relay_2_toggle );
}
//rule below added as explained in first comment.(location ngzone.run).
});
//ruke below added as explained in first commen. (location markForCheck())
this.cd.markForCheck();
}
when the page is loaded, ionViewDidEnter is called, the problem is that update_state_gui is called from the provider. the data receives in this function. isInAngularZone, tells me that it is false, out of zone. The
relay_1_toggle and relay_2_toggle are toggle button in html.
And the get not updated, i tried ngzone.run or a timeout and markForCheck(). but it does not work.
Thanks for your help
Related
I would like to listen to cell events of JupyterLab notebooks (version 3.2.0) in a custom extension. How can I do so?
a) Searching the documentation on "events" did not give helpful information:
https://jupyterlab.readthedocs.io/en/latest/search.html?q=events&check_keywords=yes&area=default
b) Here is some outdated example I could find:
Jupyter.events.on('execute.CodeCell', function(evt, data) {
// data.cell is the cell object
});
https://github.com/jupyter/notebook/issues/2321
c) Here is another outdated code snipped:
require([
"base/js/namespace",
"base/js/events"
],
function(Jupyter, events){
console.log("hello2");
events.on('notebook_loaded.Notebook', function(){
console.log("hello3");
});
events.on('app_initialized.NotebookApp', function(){
console.log("hello4");
});
});
https://github.com/jupyter/notebook/issues/2499
d) I would expect to use something like
app.events
or
var { Events } = require('#jupyterlab/events');
However, those variants did not work.
Edit
I found another code snippet:
panel.notebook.model.cells.changed.connect((list, changed) => {
if (changed.type == 'add') {
each(changed.newValues, cellmodel => {
let cell = panel.notebook.widgets.find(x => x.model.id === cellmodel.id);
// do something with cell widget.
});
}
});
https://github.com/jupyterlab/jupyterlab/issues/4316
Maybe there is no global "event registry" any more, but the events need to be accessed via the model property?
Related:
Where is a docs for Jupyter front-end extensions JavaScript API?
JupyterLab Extensions should listen to application-related events using the signal pattern which is based on lumino Signal implementation.
You can identify the signal of interest in the reference JupyterLab API Reference (which is also linked from the documentation as the last entry), for example, cell execution signal is available as NotebookActions.executed.
Extension Example
https://github.com/jupyterlab/extension-examples/tree/master/signals
Signals of NotebookActions
executed
executionScheduled
seletionExecuted
Signal of observable list
changed
Signals of individual cells
The cell model provides the signals
contentchanged
statechanged
mimetypechanged
Usage example:
function __observeNotebook(app, dependencies){
let notebook = __tryToGetNotebook(app);
if(notebook){
let cellModels = notebook.model.cells
cellModels.changed.connect(__cellsChanged, this);
for(let cellIndex=0; cellIndex < cellModels.length; cellIndex++){
let cellModel = cellModels.get(cellIndex);
__observeCell(cellModel, notebook);
}
let notebookActions = dependencies["NotebookActions"];
notebookActions.executed.connect(__cellExecuted, this); //selectionExecuted, exutionScheduled
}
}
function __observeCell(cellModel, notebook){
cellModel.contentChanged.connect(cellModel => __cellContentChanged(cellModel, notebook), this);
cellModel.stateChanged.connect(__cellStateChanged, this);
}
function __cellsChanged(cellModels, change){
console.log("Cells changed:")
console.log("type: " + change.type);
console.log("oldIndex: " + change.oldIndex);
console.log("newIndex: " + change.newIndex);
console.log("oldValues: " + change.oldValues);
console.log("newValues: " + change.newValues);
if(change.type == "add"){
var newCellModel = cellModels.get(change.newIndex);
__observeCell(newCellModel);
}
}
function __cellContentChanged(cellModel, notebook){
let id = cellModel.id
console.log("Content of cell " + id + " changed");
let currentText = cellModel.value.text;
console.log(currentText);
let cellWidget = notebook.widgets.find(widget=>{
return widget.model.id == id;
});
let outputArea = cellWidget.outputArea;
let children = outputArea.node.children;
if(children.length==1){
let output = children[0];
console.log(output);
}
}
function __cellStateChanged(cellModel, change){
let currentText = cellModel.value.text;
console.log("State of cell " + cellModel.id + " changed:");
console.log("name: " + change.name);
console.log("old value: " + change.oldValue);
console.log("new value: " + change.newValue);
}
function __cellExecuted(any, context){
let {cell, notebook, success, error} = context;
console.log("Executed cell " + cell.model.id);
}
function __tryToGetNotebookCell(app){
var notebook = __tryToGetNotebook(app);
return notebook
?notebook.activeCell
:null;
}
function __tryToGetNotebook(app){
var notebookPanel = __getFirstVisibleNotebookPanel(app);
return notebookPanel
?notebookPanel.content
:null;
}
function __getFirstVisibleNotebookPanel(app){
var mainWidgets = app.shell.widgets('main');
var widget = mainWidgets.next();
while(widget){
var type = widget.sessionContext.type;
if(type == 'notebook'){ //other wigets might be of type DocumentWidget
if (widget.isVisible){
return widget;
}
}
widget = mainWidgets.next();
}
return null;
}
I want to check response time for multiple requests sent to API, than display it on chart with help of chart.js I already have done it, but I am not sure if I am doing it right, because responses could not come and my code is adding point on chart only when client receive equal amount of responses that user entered.
here is function responsible for sending request to API and returning response time and data weight:
testRequests(numOfRequests, numOfRecords, db): Subject<any> {
const subject = new Subject();
for (let i = 1; i <= numOfRequests; i++) {
const start_time = performance.now();
this.http.get(BASE_URL + DATABASE + db + LIMIT + numOfRecords, {observe: 'response'}).subscribe((response) => {
subject.next({
time: performance.now() - start_time,
weight: response.headers.get('Content-Length')
});
});
}
return subject;
}
and here is func, that receives results and when it have same amount responses that user requested it adds point to chart:
makeTest(requestsAmount = 1, requestDB = 'aurora') {
const arrOfResults = [];
this.subscription = this.api.testRequests(requestsAmount, 5, requestDB).subscribe(
result => {
arrOfResults.push(result);
if (arrOfResults.length === +requestsAmount) {
this.lineChartData[0].data.push(arrOfResults[arrOfResults.length - 1].time);
this.lineChartData[1].data.push(arrOfResults[arrOfResults.length - 1].weight * arrOfResults.length / 1024);
this.lineChartLabels.push(arrOfResults.length + ' - ' + (requestDB === 'aurora' ? 'Aurora' : 'DynamoDB'));
this.chart.chart.update();
}
},
err => console.error(err),
() => console.log('completed')
);
}
as I heard that there is no guarantee that request will produce response, and responses can get lost, I would like to improve my code, so its generate point on chart in case there are some responses missing.
The subscribe method is not called when there is an unhandled error. You need to use a catch listener for error events.
The below example catches all errors and converts them into a null value. Now subscribe will receive either a response or null.
this.http.get(BASE_URL + DATABASE + db + LIMIT + numOfRecords, {observe: 'response'})
.catch((error, resp) => null)
.subscribe((response) => {
subject.next({
time: performance.now() - start_time,
weight: response ? response.headers.get('Content-Length') : 0
});
});
I'm trying to let users favorite a project. I'm storing these projects at 2 places so I have to update them simultaneously. After looking at the firebase docs, using transactions seemed to be the best option.
.
Function to toggle the favorite status:
function toggleFavorite (projectReference, uid) {
projectReference.transaction(function(project) {
console.log('Before-Favorites :' + project.favoriteCount);
if (project.favorites && project.favorites[uid]) {
project.favoriteCount--;
project.favorites[uid] = null;
} else {
project.favoriteCount++;
if(!project.favorites) {
project.favorites= {};
}
project.favorites[uid] = true;
}
console.log(' After-Favorites :' + project.favoriteCount);
return project;
});
};
Function to add the eventListeners to the projects:
function AddToFavorite (uid, authorId) {
const favoriteList = document.querySelectorAll('.btnFavorite');
for(var i = 0; i<favoriteList.length; i++) {
favoriteList[i].addEventListener('click', function(event) {
const projectId = this.dataset.id;
console.log(projectId);
const globalProjectRef = firebase.database().ref('/projects/' + projectId);
const userProjectRef = firebase.database().ref('/user-projects/' + authorId + '/' + projectId);
toggleFavorite(globalProjectRef,uid);
toggleFavorite(userProjectRef,uid);
});
}
}
I want to store the uid of the current user under a 'favorites' node within the project location.
When i want to store the data I can see it appearing in the database but removing it after instantly. Followed by that i get an error in the console that my project object is null.
What's the best way of solving this issue ?
I'm working on a meteor react project and want to use load data from local storage which happens async. Unfortunately I wasn't able to get the data out of callback even with binds. I tried multiple ways but could not get any of them to work, surely I'm missing something.
I stripped as much away as I could but had to keep some for the context.
From my understanding it can only be related to the track object as setting those simple Integers, Booleans works fine.
render() {
const { audioCollection } = this.props; // database collection, async hence the following if check
if (audioCollection) {
this.tracks = audioCollection.audio(); // setting tracks for later use
// make sure tracks are loaded and only run once, as we do this in the react renderer
if (this.tracks && !this.state.tracksLoaded) {
var trackLoadedCount = 0;
this.tracks.forEach((track, i) => { // I tried to use forEach and map here
// now we try to load the data from local storage and if it fails fall back to the remote server
LocalForage.getItem(track.file_id).then(function(err, file) {
if (!err && file) {
console.log(track.file_id + ' from cache')
var blob = new Blob([file]);
fileURI = window.URL.createObjectURL(blob);
} else {
console.log(track.file_id + ' from database')
fileURI = audioCollection.audioLink(track.file_id);
}
track.fileURI = fileURI; // assigning the retrieved data uri to the track object, also tried to set it on the original parent object not the extracted one from the forEach/map
console.log(fileURI + ' ' + track.fileURI) // yes, both are set
trackLoadedCount++; // increasing the tracks loaded count, to calculate if all have been loaded and to test if it can write outside of the callback, which it does
// if all files have been processed, set state loaded, this works too.
if (trackLoadedCount == this.tracks.length) {
this.setState({
tracksLoaded: true,
})
}
}.bind(track, this))
});
}
}
// once all has been processed we try to retrieve the fileURI, but it isn't set :(
if (audioCollection && this.tracks && this.state.tracksLoaded) {
console.log('all loaded ' + this.tracks.length)
this.tracks.map(track => {
console.log('track: ' + track.file_id + ' ' + track.fileURI) // file_id is set, fileURI is not
})
}
// we only log
return (
<Content {...this.props}>
<div>just console output</div>
</Content>
);
}
I tried more approaches:
Writing the tracks as an array to state like tracksLoaded (didn't work work)
Defining a new var before the async call and setting its values from within the callback, like trackLoadedCount (with and without bind) (doesn't work)
Why isn't this working while its working for tracksLoaded and trackLoadedCount?
Update regarding Firice Nguyen Answer
render() {
const { audioCollection } = this.props;
if (audioCollection) {
this.tracks = audioCollection.audio();
if (this.tracks && !this.state.tracksLoaded) {
var trackLoadedCount = 0;
this.tracks.forEach((track, i, trackArray) => {
LocalForage.getItem(track.file_id).then(function(err, file) {
if (!err && file) {
console.log(track.file_id + ' from cache')
var blob = new Blob([file]);
fileURI = window.URL.createObjectURL(blob);
} else {
console.log(track.file_id + ' from database')
fileURI = audioCollection.audioLink(track.file_id);
}
track.fileURI = fileURI;
console.log('1. ' + track.file_id + ' ' + track.fileURI);
trackArray[i] = track;
console.log('2. ' + track.file_id + ' ' + trackArray[i].fileURI);
trackLoadedCount++;
if (trackLoadedCount == this.tracks.length) {
this.setState({
tracksLoaded: true,
})
}
}.bind(track, this))
});
}
}
if (audioCollection && this.tracks && this.state.tracksLoaded) {
console.log('all loaded ' + this.tracks.length)
this.tracks.map(track => {
console.log('3. ' + track.file_id + ' ' + track.fileURI) // file_id is set, fileURI is not
})
}
return (
<Content {...this.props}>
<div>just console output</div>
</Content>
);
}
returns
MXqniBNnq4zCfZz5Q from database
1. http://localhost:3000/cdn/storage/files/MXqniBNnq4zCfZz5Q/original/MXqniBNnq4zCfZz5Q.m4a
2. http://localhost:3000/cdn/storage/files/MXqniBNnq4zCfZz5Q/original/MXqniBNnq4zCfZz5Q.m4a
keBWP6xb9PyEJhEzo from database
1. http://localhost:3000/cdn/storage/files/keBWP6xb9PyEJhEzo/original/keBWP6xb9PyEJhEzo.m4a
2. http://localhost:3000/cdn/storage/files/keBWP6xb9PyEJhEzo/original/keBWP6xb9PyEJhEzo.m4a
K2J2W9W26DDBNoCcg from database
1. http://localhost:3000/cdn/storage/files/K2J2W9W26DDBNoCcg/original/K2J2W9W26DDBNoCcg.m4a
2. http://localhost:3000/cdn/storage/files/K2J2W9W26DDBNoCcg/original/K2J2W9W26DDBNoCcg.m4a
all loaded 3
3. MXqniBNnq4zCfZz5Q undefined
3. keBWP6xb9PyEJhEzo undefined
3. K2J2W9W26DDBNoCcg undefined
hence the issue persists.
The forEach give out a copy of the element. The track is just a copy, not the original one. It does not point to the element in your array. You can try this:
this.tracks.forEach(track, i, trackArray) => {
// change `track` value
...
trackArray[i] = track;
});
Or try map method
I have a table called Subscription and another table called Client I need the gender of the Client who owns the subscription every time I make an update. Here's my update script:
function update(item, user, request) {
var subscriptionId = item.id;
var subscriptionActivitiesTable = tables.getTable("SubscriptionActivity");
var userTable = tables.getTable("User");
var activityTable = tables.getTable("Activity");
var userGender = userTable.where({id: item.UserId}).select('Gender').take(1).read();
console.log(userGender);
activityTable.where({PlanId:item.PlanId, Difficulty: item.Difficulty}).read({
success: function(results){
var startDate = item.StartDate;
results.forEach(function(activity)
{
var testDate = new Date(startDate.getFullYear(),startDate.getMonth(), startDate.getDate());
testDate.setDate(testDate.getDate() + activity.Sequence + (activity.Week*7));
subscriptionActivitiesTable.insert({SubscriptionId: subscriptionId,
ActivityId: activity.id, ShowDate: new Date(testDate.getFullYear(),
testDate.getMonth(), testDate.getDate()), CreationDate: new Date()});
})
}
});
var planWeeks = 12;//VER DE DONDE SACAMOS ESTE NUMERO
var idealWeight = 0;
if (userGender === "Male")
{
idealWeight = (21.7 * Math.pow(parseInt(item.Height)/100,2));
}
else
{
idealWeight = (23 * Math.pow(parseInt(item.Height)/100,2));
}
var metabolismoBasal = idealWeight * 0.95 * 24;
var ADE = 0.1 * metabolismoBasal;
var activityFactor;
if (item.Difficulty === "Easy")
{
activityFactor = 1.25;
}
else if(item.Difficulty === "Medium")
{
activityFactor = 1.5;
}
else
{
activityFactor = 1.75;
}
var caloricRequirement = ((metabolismoBasal + ADE)*activityFactor);
activityTable.where(function(item, caloricRequirement){
return this.PlanId === item.PlanId && this.Type != "Sport" &&
this.CaloricRequirementMin <= caloricRequirement &&
this.CaloricRequirementMax >= caloricRequirement;}, item, caloricRequirement).read({
success: function(results)
{
var startDate = item.StartDate;
results.forEach(function(activity)
{
for (var i=0;i<planWeeks;i++)
{
var testDate = new Date(startDate.getFullYear(),startDate.getMonth(), startDate.getDate());
testDate.setDate(testDate.getDate() + activity.Sequence + (i*7));
subscriptionActivitiesTable.insert({SubscriptionId: subscriptionId,
ActivityId: activity.id, ShowDate: new Date(testDate.getFullYear(),
testDate.getMonth(), testDate.getDate()), CreationDate: new Date()});
}
})
}
})
request.execute();
}
I tried the code above and clientGender is undefined. As you can see I want to use the gender to set the idealWeight.
The read() method expects a function to be passed in on the success parameter - it doesn't return the result of the query like you'd think.
Try something like this instead:
function update(item, user, request) {
var clientTable = tables.getTable("Client");
var clientGender = 'DEFAULT';
clientTable.where({id: item.ClientId}).select('Gender').take(1).read({
success: function(clients) {
if (clients.length == 0) {
console.error('Unable to find client for id ' + item.ClientId);
} else {
var client = client[0];
clientGender = client.Gender;
// since we're inside the success function, we can continue to
// use the clientGender as it will reflect the correct value
// as retrieved from the database
console.log('INSIDE: ' + clientGender);
}
}
});
// this is going to get called while the clientTable query above is
// still running and will most likely show a value of DEFAULT
console.log('OUTSIDE: ' + clientGender);
}
In this sample, the client table query is kicked off, with a callback function provided in the success parameter. When the query is finished, the callback function is called, and the resulting data is displayed to the log. Meanwhile - while the query is still running, that is - the next statement after the where/take/select/read fluent code is run, another console.log statment is executed to show the value of the clientGender field outside the read function. This code will run while the read statement is still waiting on the database. Your output should look something like this in the WAMS log:
* INSIDE: Male
* OUTSIDE: Default
Since the log shows the oldest entries at the bottom, you can see that the OUTSIDE log entry was written sometime before the INSIDE log.
If you're not used to async or functional programming, this might look weird, but as far as I've found, this is now node works. Functions nested in functions nested in functions can get kind of scary, but if you plan ahead, it probably won't be too bad :-)