how to get excel cell data changed event using new api or Excel object in office.js - office-addins

I am trying to find out how to get cell changed event using the Excel object
Excel.run(function (ctx) {
}
in office 2016.
is the context used by Office.context.document is same as context used in run function

found the answer for this.
Binding concept used earlier can be used now also as shown in the example https://github.com/OfficeDev/office-js-docs/blob/master/reference/excel/bindingcollection.md
(function () {
// Create myTable
Excel.run(function (ctx) {
var table = ctx.workbook.tables.add("Sheet1!A1:C4", true);
table.name = "myTable";
return ctx.sync().then(function () {
console.log("MyTable is Created!");
//Create a new table binding for myTable
Office.context.document.bindings.addFromNamedItemAsync("myTable", Office.CoercionType.Table, { id: "myBinding" }, function (asyncResult) {
if (asyncResult.status == "failed") {
console.log("Action failed with error: " + asyncResult.error.message);
}
else {
// If successful, add the event handler to the table binding.
Office.select("bindings#myBinding").addHandlerAsync(Office.EventType.BindingDataChanged, onBindingDataChanged);
}
});
})
.catch(function (error) {
console.log(JSON.stringify(error));
});
});
// When data in the table is changed, this event is triggered.
function onBindingDataChanged(eventArgs) {
Excel.run(function (ctx) {
// Highlight the table in orange to indicate data changed.
var fill = ctx.workbook.tables.getItem("myTable").getDataBodyRange().format.fill;
fill.load("color");
return ctx.sync().then(function () {
if (fill.color != "Orange") {
ctx.workbook.bindings.getItem(eventArgs.binding.id).getTable().getDataBodyRange().format.fill.color = "Orange";
console.log("The value in this table got changed!");
}
else
})
.then(ctx.sync)
.catch(function (error) {
console.log(JSON.stringify(error));
});
});
}
})();

Related

Cannot read property 'emit' of undefined when trying to emit a document

I am trying to create a design for tags of entities in PouchDB with ReactJS. I managed to save my design using the put function, but when I query my design, the response is just an empty array and I am getting following error in console:
TypeError: Cannot read property 'emit' of undefined
I think the problem is in my function that I later use as a map parameter to my design variable:
function emitTagsMap(doc)
{
if (doc !== undefined)
{
if (Array.isArray(doc.tags))
{
doc.tags.forEach(x =>
{
/* Here is probably the problem - this.db is undefined */
this.db.emit(x, null);
});
}
}
};
this.db is declared in constructor:
constructor(service, name)
{
if (!service || !name) throw new Error("PouchDatabase initialized incorrectly");
this.name = name;
this.db = new PouchDB(name);
this.service = service;
this.tagsView();
}
Please bare in mind that I am completely new to PouchDB.
Any ideas how can I initialize the emit function?
Thank you in advance.
I assume, that your function is a part of a JavaScript class (otherwise you have to explain the idea with this). In ES6, you have to bind this to your regular functions. You have two options:
First - bind it via constructor:
constructor() {
this.emitTagsMap = this.emitTagsMap.bind(this);
}
Second - declare the function as an arrow one. This way, react will bind it for you:
emitTagsMap = (doc) =>
{
if (doc !== undefined)
{
if (Array.isArray(doc.tags))
{
doc.tags.forEach(x =>
{
/* Here is probably the problem - this.db is undefined */
this.db.emit(x, null);
});
}
}
};
You don't need to call emit over the database object.
Try this:
function emitTagsMap(doc)
{
if (doc !== undefined)
{
if (Array.isArray(doc.tags))
{
doc.tags.forEach(x =>
{
emit(x, null);
});
}
}
};
According to the PouchDB docs a design document is formed like this:
// first create a new design doc and pass your map function as string into it
var ddoc = {
_id: "_design/my_index",
views: {
by_name: {
map: "function (doc) { if (doc !== undefined) { if (Array.isArray(doc.tags)) { doc.tags.forEach(x => { emit(x, null); }); } } }"
}
}
};
// save it
db.put(ddoc).then(function () {
// success!
}).catch(function (err) {
// some error (maybe a 409, because it already exists?)
});
//Then you actually query it, by using the name you gave the design document when you saved it:
db.query('my_index/by_name').then(function (res) {
// got the query results
}).catch(function (err) {
// some error
});
https://pouchdb.com/guides/queries.html

Array populated in debug more but not in in normal mode in Node.js

In the code below, when I run in debug mode with a break-point at this line: content.push(data.Body.toString()); I can see that data is inserted to the content array.
However when I run the code normally, content comes back empty.
How can I get it to populate the array for downstream use?
var params = { Bucket: "thebucket", Prefix: "theprefix/" }
var content = [];
function getS3Data()
{
var s3 = new aws.S3();
s3.listObjects(params, function (err, data)
{
if (err) throw err; // an error occurred
else
{
var i;
for (i = 0; i < data.Contents.length; i++)
{
var currentValue = data.Contents[i];
if(currentValue.Key.endsWith(params.Prefix) == false)
{
var goParams = { Bucket: params.Bucket, Key: currentValue.Key };
s3.getObject(goParams, function(err, data)
{
if (err) throw err; //error
content.push(data.Body.toString());
});
};
};
}//else
});//listObjects
}//getS3Data
getS3Data();
console.log(content); //prints empty here when run in non-debug.
The line:
console.log(content)
is being executed before the line:
content.push(data.Body.toString());
the function you are passing as a 2nd argument to s3.listObjects will be executed asynchronously. If you want to log out content you need to do it within the callback function meaning:
s3.listObjects(params, function (err, data) {
if (err) throw err;
else {
// ...
console.log(content)
}
});
A better approach would be to implement getS3Data with Promise so you can run code after the object listing is done for sure.
function getS3Data() {
return new Promise((resolve, reject) => {
if (err) {
reject(err)
} else {
const promises = []
for (const i = 0; i < data.Contents.length; i++) {
const currentValue = data.Contents[i];
if (currentValue.Key.endsWith(params.Prefix) == false) {
const goParams = { Bucket: params.Bucket, Key: currentValue.Key };
promises.push(new Promise((res, rej) => {
s3.getObject(goParams, function (err, data) {
if (err) {
rej(err); //error
} else {
res(data.Body.toString());
}
});
}));
}
}
Promise.all(promises).then(resolve);
}
});
}
getS3Data()
.then(result => { // this will actually be `content` from your code example
console.log(result);
}).catch(error => {
console.error(error);
})
Node.js' documentation has an example very similar to the problem you are experiencing:
Dangers of Mixing Blocking and Non-Blocking Code
The issue arises because the variable content is not set as soon as getS3Data has finished, because it is an asynchronous function. content will be set some time later. But your call to console.log(content); will execute immediately after getS3Data has finished, so at that point content has not been set yet.
You can test that by adding an extra log:
s3.getObject(goParams, function(err, data)
{
if (err) throw err; //error
content.push(data.Body.toString());
console.log("Content has been assigned");
});
And then change the bottom to:
getS3Data();
console.log("getS3Data has finished", content);
It's likely you'll get the messages in this order:
getS3Data has finished
Content has been assigned

Querying collection using array meteor js

I have this weird scenario which I do not know what the problem is exactly. While troubleshooting I found out that the subscription is published and subscribed to because it's printed on the console. When I executed this on Firefox console it displayed this error SyntaxError: missing : after property id [Learn More]. I don't know what the syntax error is as the same code works on other files.
If I remove fetch() function from it it displayed 2 obects being published. This means the publish and sbscription is working. What am I to do right?
This is the event function
students(){
let myslug = trimInput(Session.get('ReceivedSlug'));
if (myslug) {
let mySchoolDoc = SchoolDb.findOne({slug: myslug});
if (mySchoolDoc) {
let arrayModuleSchool = StudentSchool.find({schoolId: mySchoolDoc._id});
if (arrayModuleSchool) {
var arrayStudentIds = [];
arrayModuleSchool.forEach(function(studentSchool){
arrayStudentIds.push(studentSchool.studentId);
});
let subReadiness = SchoolStudents.find({ _id: {$in: arrayStudentIds}}).fetch();
if (subReadiness) {
console.log('before readiness --- ' +arrayStudentIds);
console.log('after seting --- ' +subReadiness);
return subReadiness;
}
}
}
}
}
This is the publish function
Meteor.publish('PaginatedStudents', function (skipCount) {
check(skipCount, Number);
user = Meteor.users.findOne({_id:this.userId})
if(user) {
if(user.emails[0].verified) {
return SchoolStudents.find({userId: this.userId}, {limit: 2, skip: skipCount});
} else {
throw new Meteor.Error('Not authorized');
return false;
}
}
});
Tracker to rerun when things changes
Session.setDefault('skip', 0);
Tracker.autorun(function () {
Meteor.subscribe('PaginatedStudents', Session.get('skip'));
});

Qooxdoo Remote table getRowCount() return 0

qx.Class.define("webApp.backendjs.tables.RegionesModel", {
extend: qx.ui.table.model.Remote,
members: {
_loadRowCount: function () {
var params = {};
params.action = "getCount";
var rpc = new qx.io.remote.Rpc("http://qx.alpali.cl/svc/svc.php");
rpc.setProtocol("2.0");
rpc.setCrossDomain(true);
rpc.callAsync(qx.lang.Function.bind(this._onRowCountCompleted, this), "regiones.regiones.getNominaRegiones", params);
},
_onRowCountCompleted: function (result, exc) {
if (result !== null) {
this._onRowCountLoaded(result.count);
}
},
_loadRowData: function (firstRow, lastRow) {
var params = {};
params.action = "getData";
var rpc = new qx.io.remote.Rpc("http://qx.alpali.cl/svc/svc.php");
rpc.setProtocol("2.0");
rpc.setCrossDomain(true);
rpc.callAsync(qx.lang.Function.bind(this._onLoadRowDataCompleted, this), "regiones.regiones.getNominaRegiones", params);
},
_onLoadRowDataCompleted: function (result, exc) {
if (result !== null) {
this._onRowDataLoaded(result);
}
}
}
});
var RTRegionesModel = new webApp.backendjs.tables.RegionesModel();
RTRegionesModel.setColumns(["ID", "Cè´¸digo", "Nombre"], ["id", "region_id", "region_nombre"]);
var TableRegiones = new qx.ui.table.Table(RTRegionesModel);
TableRegiones.setTableModel(RTRegionesModel);
// THIS don't work, return 0
TableRegiones.addListener('appear', function () {
console.log("RTRegionesModel.getRowCount(): %s", RTRegionesModel.getRowCount());
}, RTRegionesModel);
// THIS don't work, return 0
TableRegiones.addListener('appear', function () {
console.log("RTRegionesModel.getRowCount(): %s", RTRegionesModel.getRowCount());
}, this);
this.getRoot().add(TableRegiones);
var button1 = new qx.ui.form.Button("How many record...", "icon/22/apps/internet-web-browser.png");
this.getRoot().add(button1,{right:50,top:50});
// this is ok, return teh value
button1.addListener("execute", function(e) {
console.log("RTRegionesModel.getRowCount(): %s", RTRegionesModel.getRowCount());
});
url for testing playground
i need the valor when remote table is loaded
what is the problem..???
thank.
PD: sorry for my bad and ugly english, my native language is spanish (chile), my best friend in this moment is googol
At the time that you are looking for the row count with your "THIS don't work" comment, the row count is not yet available because the network operation to retrieve the row count from the server has not yet been issued.
You probably want to be listening for the model's dataChanged event which is fired when a row count is loaded, or when the model data changes, such as this:
TableRegiones.getTableModel().addListener(
'dataChanged',
function ()
{
console.log(
"dataChanged: RTRegionesModel.getRowCount(): %s",
RTRegionesModel.getRowCount());
},
RTRegionesModel);

CloudantDB & NodeJS: Query data with specific id

I just created a NodeJS cloudantDB web starter on bluemix. Then, I have a API get data from cloudantDB and get successfull but it returns all data. Please see js file:
js file:
app.get('/api/provider', function(request, response) {
console.log("Get method invoked.. ")
db = cloudant.use(dbCredentials.dbProvider);
var docList = [];
var i = 0;
db.list(function(err, body) {
if (!err) {
var len = body.rows.length;
console.log('total # of docs -> '+len);
if(len == 0) {
// error
} else {
body.rows.forEach(function(document) {
db.get(document.id, { revs_info: true }, function(err, doc) {
if (!err) {
if(doc['_attachments']) {
// todo
} else {
var responseData = createResponseDataProvider(
doc._id,
doc.provider_type,
doc.name,
doc.phone,
doc.mobile,
doc.email,
doc.logo,
doc.address
);
}
docList.push(responseData);
i++;
if(i >= len) {
response.write(JSON.stringify(docList));
console.log('ending response...');
response.end();
}
} else {
console.log(err);
}
});
});
}
} else {
console.log(err);
}
});
If I want to add parameter to API to get specific data from DB , Do we need create search index or query on cloudant, afer that call API the same : app.get('/api/provider/:id'). Please help me review and sharing. Thanks
you could get the document by id/name:
db.get(docID, function(err, data) {
// do something
});
references:
https://github.com/apache/couchdb-nano#document-functions
https://github.com/cloudant/nodejs-cloudant#api-reference
You can use a search function of Cloudant.
You need to create search index. In search index you can manage what data you want to get.
Example: https://cloudant.com/for-developers/search/
Following this code after create search index.
...
var query = {q: "id:doc.id"};
db.search('design document name', 'index name', query, function(er, result) {
if (er) {
throw er;
}
console.log(result);
});

Resources