I have written my code in the process of inserting a table to the word document. My code worked successfully before, but when I run it now, it is giving an exception:
"ItemNotFound: ItemNotFound\n at Anonymous function (https://appsforoffice.microsoft.com/lib/beta/hosted/word-win32-16.01.js:21:198669)\n
at yi (https://appsforoffice.microsoft.com/lib/beta/hosted/word-win32-16.01.js:21:220646)\n
at st (https://appsforoffice.microsoft.com/lib/beta/hosted/word-win32-16.01.js:21:220733)\n
at d (https://appsforoffice.microsoft.com/lib/beta/hosted/word-win32-16.01.js:21:220553)\n
at c (https://appsforoffice.microsoft.com/lib/beta/hosted/word-win32-16.01.js:21:219139)"
The error location is showing as
"errorLocation":"Range.ParentTable"
I have no idea why the code is not running now. I have wrote this code in January. If anyone could, please help me to identify what is wrong in the below code.
my code :
this.insertTable = function () {
Word.run(function (context) {
var range = context.document.getSelection();
var tableDataJsonString;
if (range.parentTable != null) {
var parentTable = range.parentTable;
var parent_ContentController; //Content controller where the table has been inserted.
var parent_contentController_id;
var parent_contentController_tag;
var parent_name; //Section or Element name
var parent_id; //Section or Element's id
var table_style; //Table style
var count;
var header_rowCount;
var body_rowCount;
var columns;
var footer_rowCount;
parentTable.load('rowCount');
parentTable.load('headerRowCount');
return context.sync().then(function () {
if (parentTable.rowCount != null) {
}
}).then(function () {
existing_table.setTableProperties(parent_contentController_id, parent, parent_id, body_rowCount, columns, header_rowCount, footer_rowCount);
//tableDataJsonString = JSON.stringify(tableData);
context.sync();
if (count == null) {
_self.selectTableDlg(false, existing_table);
}
else if (count != 0) {
_self.selectTableDlg(true, existing_table);
}
}).catch(function (error) {
showAlert('Exception');
});
}
}).catch(function (error) {
console.log('Error: ' + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
}
Code is not going through the 'return context.sync().then(function () {' and return an exception.
First of all, if the code was written back in January it was using the PREVIEW APIs, who are subject to change, we apologize about this and thanks for trying them!
On this case we have minor change associated on how NULL works, the error is how to check if the table exists. So effectively, you need to make a few changes to make your code work. btw There is a bit more detail on this answer who conceptually is the same issue as this one.
Here is some code on how you need to check if the selection is inside a table, and in general how we handle properties and methods that could return null.
Just adjust your code accordingly and it should work.
Word.run(function (context) {
//you can get parteTable (will rise an exception if null) or parentTableOrNullObject (never throws an exception and lets you check if its null or not using isNullObject property)
var myTable = context.document.getSelection().parentTableOrNullObject;
context.load(myTable);
return context.sync()
.then(function () {
if (myTable.isNullObject)
console.log("the selecion is NOT in a table");
else
console.log("the selection is within a table");
})
})
Related
What I'm trying to do:
Figure out how to reference/grab geoJSON data from a server.
In this case I'm just using an example on the openLayers doc.
Ideally I'd just be able to print out a features ID/type, but I cannot get it to work.
What's happening:
var selectElement = document.getElementById('type');
var source = vector.getSource();
var feature = source.getFeatures()[0];
var changeInteraction = function() {
if (select !== null) {
map.removeInteraction(select);
}
var value = selectElement.value;
if (value == 'singleclick') {
select = selectSingleClick;
} else if (value == 'click') {
select = selectClick;
} else if (value == 'pointermove') {
select = selectPointerMove;
} else if (value == 'altclick') {
select = selectAltClick;
} else {
select = null;
}
if (select !== null) {
map.addInteraction(select);
select.on('select', function(e) {
document.getElementById('status').innerHTML = feature.getGeometry().getType();
});
console.log(feature);
}
};
I was hoping my innerHTML would display "Polygon" in this case, but no such luck. I've tried various combinations, and been looking over the documentation, can't see what I'm doing wrong.
The server I'm trying to grab the info from is,
https://openlayers.org/en/v4.6.4/examples/data/geojson/countries.geojson
Any help would be appreciated.
(I can attach full code if helpful)
I was able to replicate your program and find the solution for retrieving the Country's name for a selected feature, as mentioned in your comments.
First, remove the following lines. You don't want the first feature of the source file but the first selected feature instead.
var source = vector.getSource();
var feature = source.getFeatures()[0];
Second, define the feature inside the callback function(e) for the select Event. Also, since getFeatures() will return a Collection of features the getArray() method is necessary.
The get(key) method will return a value for a determined key, "name" in this case.
if (select !== null) {
map.addInteraction(select);
select.on('select', function(e) {
var feature = e.target.getFeatures().getArray()[0];
document.getElementById('status').innerHTML = ' ' +
feature.get("name") + ' ' + feature.getId();
});
}
I think I'm on the wrong track here:
I have an event source that gives me updates on the underlying system oprations. The page is intended to show said events in a jquery powered treetable. I receieve the events perfectly but I realized that there were a case I did not handle, the case where an event arrives but is missing it's parent. In this case I need to fetch the missing root plus all potentially missing children of that root node from the database. This works fine too.
//init fct
//...
eventSource.addEventListener("new_node", onEventSourceNewNodeEvent);
//...
function onEventSourceNewNodeEvent(event) {
let data = event.data;
if (!data)
return;
let rows = $(data).filter("tr");
rows.each(function (index, row) {
let parentEventId = row.getAttribute("data-tt-parent-id");
let parentNode = _table.treetable("node", parentEventId);
// if headless state is not fully
// resolved yet keep adding new rows to array
if (headlessRows[parentEventId]) {
headlessRows[parentEventId].push(row);
return;
} else if (parentEventId && !parentNode) { // headless state found
if (!headlessRows[parentEventId])
headlessRows[parentEventId] = [];
headlessRows[parentEventId].push(row);
fetchMissingNodes(parentEventId);
return;
}
insertNode(row, parentNode);
});
}
function fetchMissingNodes(parentEventId) {
let url = _table.data("url") + parentEventId;
$.get(url, function (data, textStatus, request) {
if (!data)
return;
let rows = $(data).filter("tr");
//insert root and children into table
_table.treetable("loadBranch", null, rows);
let parentNode = _table.treetable("node", parentEventId);
let lastLoadedRow = $(rows.last());
let headlessRowsArray = headlessRows[parentEventId];
while (headlessRowsArray && headlessRowsArray.length > 0) {
let row = headlessRowsArray.shift();
let rowId = row.getAttribute("data-tt-id");
if (rowId <= lastLoadedRow) // already loaded event from previous fetch
continue;
insertNode(row, parentNode);
let pendingUpdatesArray = pendingUpdates[rowId];
// shouldn't be more than one but who know future versions
while (pendingUpdatesArray && pendingUpdatesArray.length > 0) {
let updateEvent = headlessRowsArray.shift();
updateNode(updateEvent)
}
delete pendingUpdates[rowId]; // <- something better here?
}
delete headlessRows[parentEventId]; // <- something better here too?
});
}
The problem is around the line if (headlessRows[parentEventId]).
When I run it step by step (putting a debugger instruction just before) everything works fine, the headless array is created and filled correctly.
But as soon as I let it run full speed everything breaks.
The logs I printed seems to indicate that the array is not behaving in the way I was expecting it to. If I print the array with a console.log it shows as follow :
(2957754) [empty × 2957754]
length : 2957754
__proto__ : Array(0)
It seems to be missing any actual data. whereas it shows as follow when I execute it step by step:
(2957748) [empty × 2957747, Array(1)]
2957747:[tr.node.UNDETERMINED]
length:2957748
__proto__:Array(0)
I'm missing something but it is still eluding me.
your code is async, you do http request but you treat him as synchronized code.
try this fix
//init fct
//...
eventSource.addEventListener("new_node", onEventSourceNewNodeEvent);
//...
async function onEventSourceNewNodeEvent(event) {
let data = event.data;
if (!data)
return;
let rows = $(data).filter("tr");
rows.each(function (index, row) {
let parentEventId = row.getAttribute("data-tt-parent-id");
let parentNode = _table.treetable("node", parentEventId);
// if headless state is not fully
// resolved yet keep adding new rows to array
if (headlessRows[parentEventId]) {
headlessRows[parentEventId].push(row);
return;
} else if (parentEventId && !parentNode) { // headless state found
if (!headlessRows[parentEventId])
headlessRows[parentEventId] = [];
headlessRows[parentEventId].push(row);
await fetchMissingNodes(parentEventId);
return;
}
insertNode(row, parentNode);
});
}
function fetchMissingNodes(parentEventId) {
return new Promise((resolve,reject) =>{
let url = _table.data("url") + parentEventId;
$.get(url, function (data, textStatus, request) {
if (!data){
resolve()
return;
}
let rows = $(data).filter("tr");
//insert root and children into table
_table.treetable("loadBranch", null, rows);
let parentNode = _table.treetable("node", parentEventId);
let lastLoadedRow = $(rows.last());
let headlessRowsArray = headlessRows[parentEventId];
while (headlessRowsArray && headlessRowsArray.length > 0) {
let row = headlessRowsArray.shift();
let rowId = row.getAttribute("data-tt-id");
if (rowId <= lastLoadedRow) // already loaded event from previous fetch
continue;
insertNode(row, parentNode);
let pendingUpdatesArray = pendingUpdates[rowId];
// shouldn't be more than one but who know future versions
while (pendingUpdatesArray && pendingUpdatesArray.length > 0) {
let updateEvent = headlessRowsArray.shift();
updateNode(updateEvent)
}
delete pendingUpdates[rowId]; // <- something better here?
}
delete headlessRows[parentEventId]; // <- something better here too?
resolve()
});
})
}
So I am trying to write javascript code for a ribbon button in Dynamics CRM 2016 that will grab a phone number from a list of Leads that can be seen in the Active Leads window.
However, when I try to run it, I get an error telling me
As I step into my code (I'm debugging), I see this error
Here is the code I am working with.
function updateSelected(SelectedControlSelectedItemIds, SelectedEntityTypeName) {
// this should iterate through the list
SelectedControlSelectedItemIds.forEach(
function (selected, index) {
//this should get the id and name of the selected lead
getPhoneNumber(selected, SelectedEntityTypeName);
});
}
//I should have the lead ID and Name here, but it is returning null
function getPhoneNumber(id, entityName) {
var query = "telephone1";
Sdk.WebApi.retrieveRecord(id, entityName, query, "",
function (result) {
var telephone1 = result.telephone1;
// I'm trying to capture the number and display it via alert.
alert(telephone1);
},
function (error) {
alert(error);
})
}
Any help is appreciated.
What you have is an javascript error. In js you can only use forEach on an array. SelectedControlSelectedItemIds is an object not an array.
To loop though an object, you can do the following.
for (var key in SelectedControlSelectedItemIds){
if(SelectedControlSelectedItemIds.hasOwnProperty(key)){
getPhoneNumber(SelectedControlSelectedItemIds[key], SelectedEntityTypeName)
}
}
Okay, so I figured it out. I had help, so I refuse to take full credit.
First, I had to download the SDK.WEBAPI.
I then had to add the webAPI to my Javascript Actions in the Ribbon Tool Bench.
Then, I had to create a function to remove the brackets around the
SelectedControlSelectedItemIds
Firstly, I had to use the API WITH the forEach method in order for it to work.
These are the revisions to my code.
function removeBraces(str) {
str = str.replace(/[{}]/g, "");
return str;
}
function updateSelected(SelectedControlSelectedItemIds, SelectedEntityTypeName) {
//alert(SelectedEntityTypeName);
SelectedControlSelectedItemIds.forEach(
function (selected, index) {
getPhoneNumber(removeBraces(selected), SelectedEntityTypeName);
// alert(selected);
});
}
function getPhoneNumber(id, entityName) {
var query = "telephone1";
SDK.WEBAPI.retrieveRecord(id, entityName, query, "",
function (result) {
var telephone1 = result.telephone1;
formatted = telephone1.replace(/[- )(]/g,'');
dialready = "1" + formatted;
withcolon = dialready.replace(/(.{1})/g,"$1:")
number = telephone1;
if (Xrm.Page.context.getUserName() == "Jerry Ryback") {
url = "http://111.222.333.444/cgi-bin/api-send_key";
} else if(Xrm.Page.context.getUserName() == "Frank Jane") {
url = "http://222.333.444.555/cgi-bin/api-send_key";
}
else if( Xrm.Page.context.getUserName() == "Bob Gilfred"){
url = "http://333.444.555.666/cgi-bin/api-send_key";
}
else if( Xrm.Page.context.getUserName() == "Cheryl Bradley"){
url = "http://444.555.666.777/cgi-bin/api-send_key";
}
else if( Xrm.Page.context.getUserName() == "Bill Dunny"){
url = "http://555.666.777.888/cgi-bin/api-send_key";
}
if (url != "") {
var params = "passcode=admin&keys=" + withcolon + "SEND";
var http = new XMLHttpRequest();
http.open("GET", url + "?" + params, true);
http.onreadystatechange = function () {
if (http.readyState == 4 && http.status == 200) {
alert(http.responseText);
}
}
http.send(null);
}
},
function (error) {
// alert(error);
})
}
To elaborate, once I successfully get the number, I remove the parenthesis, dashes and white-space. Then, I add a "1" to the beginning. Finally, I insert colons in between each number. Then, I create an HTTP command and send it to the office phone of whoever is using CRM at the time. The user eval and HTTP message is my code. I'm showing you all of this because it was a great learning experience, and this feature really adds to the functionality.
I hope some of you find this useful.
Thanks for the help.
I have the following function which selects a category from a list of available categories. This function works fine in my first test. But the same function with a different valid category name in my second test fails with the following error.
Error: Index out of bound. Trying to access element at index: 0, but there are only 0 elements that match locator By.cssSelector(".grid-view-builder__category")
this.categoryElements = element.all(by.css('.grid-view-builder__category'));
this.selectCategory = function (categoryName) {
var filteredCategories = this.categoryElements.filter(function (category) {
return category.getText().then(function (text) {
log.info(text);
return text === categoryName;
})
})
filteredCategories.first().click().then(function () {
log.info("Select Category: " + categoryName);
}).then(null, function (err) {
log.error("Category: " + categoryName + " Not Found !!" + err);
});
}
Spec File
var columnSelect = require('pages/grid/columns/columnselector-page')()
it('Add Publisher ID Column to the Grid & Verify', function () {
var columnCountBefore = columnSelect.getColumnCount();
columnSelect.openColumnSelector();
columnSelect.selectCategory('Advanced');
columnSelect.selectColumn('Publisher ID');
columnSelect.apply();
var columnCountAfter = columnSelect.getColumnCount();
expect(columnCountAfter).toBeGreaterThan(columnCountBefore);
});
The problem might be in the way you are defining and using Page Objects. Here is a quick solution to try - if this would help, we'll discuss on why that is happening.
Make the categoryElements a function instead of being a property:
this.getCategoryElements = function () {
return element.all(by.css('.grid-view-builder__category'));
};
this.selectCategory = function (categoryName) {
var filteredCategories = this.getCategoryElements().filter(function (category) {
return category.getText().then(function (text) {
log.info(text);
return text === categoryName;
})
})
filteredCategories.first().click().then(function () {
log.info("Select Category: " + categoryName);
}).then(null, function (err) {
log.error("Category: " + categoryName + " Not Found !!" + err);
});
}
Or, this could be a "timing issue" - let's add an Explicit Wait via browser.wait() to wait for at least a single category to be present:
var EC = protractor.ExpectedConditions;
var category = element(by.css('.grid-view-builder__category'));
browser.wait(EC.presenceOf(category), 5000);
It looks like this has nothing to do with the code posted here, only that the css selector you're using is not finding any elements
I'm getting the following error when attempting to get an enumerator for a collection of lists: "Uncaught Error: The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested."
It happens on the line var listEnumerator = lists.getEnumerator(); it seems to me that there is an issue in my attempt to load lists into the client object with context.load(lists);
Here's the portion of my code that's causing the problem. I've marked the place just before the error is thrown.
//____________________________Required function for accessing the host site's info.___________________________________
function getQueryStringParameter(param) {
var params = document.URL.split("?")[1].split("&");
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == param) {
return singleParam[1];
}
}
}
//____________________________Begin checking for list_________________________
function checkForList(listToFind, typeOfListToCreateIfTheListIsMissing)
{
var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
var hostcontext = new SP.AppContextSite(context, hostUrl);
var hostweb = hostcontext.get_web();
var lists = hostweb.get_lists();
context.load(lists);
context.executeQueryAsync(checkIfListExistsUsingEnumerator(listToFind, lists, hostweb, typeOfListToCreateIfTheListIsMissing), onQueryFailed);
}
//Failed to get lists for some reason
function onQueryFailed(sender, args) {
alert('We failed to retrieve lists. \n' + args.get_message() + '\n' + args.get_stackTrace());
}
//____________________________Does list exist?____________________________
function checkIfListExistsUsingEnumerator(listToFind, lists, hostweb, typeOfList)
{
var listExists = false;
//!!!!!!!!!!!!!!! ERROR HERE !!!!!!!!!!!!!!!!
var listEnumerator = lists.getEnumerator();
var title;
while (listEnumerator.moveNext())
{
title = listEnumerator.get_current().get_title();
if (title == listToFind)
{
listExists = true;
}
}
if (!listExists)
{
alert("It appears that a required list does not already exist. \nClick ok, and we'll automatically create one for you.");
//Create a new list
createList(listToFind, hostweb, typeOfList);
}
else if (listExists)
{
//Do nothing.
}
}
//____________________________If it doesn't, create one on the local site____________________________
function createList(nameOfNewList, hostweb, typeOfList) {
var listCreationInfo = new SP.ListCreationInformation();
listCreationInfo.set_title(nameOfNewList);
if (typeOfList === "events")
{
listCreationInfo.set_templateType(SP.ListTemplateType.events);
}
else if (typeOfList === "contacts")
{
listCreationInfo.set_templateType(SP.ListTemplateType.contacts);
}
var lists = hostweb.get_lists();
var newList = lists.add(listCreationInfo);
context.load(newList);
context.executeQueryAsync(onListCreationSuccess, onListCreationFail);
}
function onListCreationSuccess() {
alert('List created successfully!');
}
function onListCreationFail(sender, args) {
alert('Failed to create the list. ' + args.get_message());
}
I've looked at this question sharepoint javascript collection not initialized error which seems to be fairly similar to mine, but I'm having trouble implementing the solution provided there, making me think my error may be have a different cause.
I've also tried querying for the lists inside of the function that is throwing the error, but that doesn't seem to solve anything.
For a little background, these functions are attempting to read all lists from the app's host site, check to see if a specified list exists, and create a list if no matching list exists. If there's a better way of doing that than what I'm attempting, I'd be open to that too.
Any pointers?
Some things I've tried that don't seem to work:
Changing the Asynchronous query
context.executeQueryAsync(checkIfListExists(listToFind, hostweb, typeOfListToCreateIfTheListIsMissing), onQueryFailed);
to a Synchronous one.
context.executeQuery(checkIfListExists(listToFind, hostweb, typeOfListToCreateIfTheListIsMissing), onQueryFailed);
I've figured out an alternate, and shorter way to method of achieving the same goal I was trying to achieve before.
Instead of checking to see if a list does not already exist, I just try to create a list, and the Query fails to create a list if one is already there. (That's good because I don't want to overwrite the list if it is already there.)
I'm not totally sure if there are any undesired side effects of what I'm doing here, but in my tests it produced the desired behavior.
//____________________________Required function for accessing the host site's info.___________________________________
function getQueryStringParameter(param) {
var params = document.URL.split("?")[1].split("&");
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == param) {
return singleParam[1];
}
}
}
//____________________________Create a list if one does not already exist_________________________
function createList(listToCreate, typeOfList)
{
// Create an announcement SharePoint list with the name that the user specifies.
var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
var hostContext = new SP.AppContextSite(currentContext, hostUrl);
var hostweb = hostContext.get_web();
var listCreationInfo = new SP.ListCreationInformation();
listCreationInfo.set_title(listToCreate);
if (typeOfList === "events")
{
listCreationInfo.set_templateType(SP.ListTemplateType.events);
}
else if (typeOfList === "contacts")
{
listCreationInfo.set_templateType(SP.ListTemplateType.contacts);
}
var lists = hostweb.get_lists();
var newList = lists.add(listCreationInfo);
currentContext.load(newList);
currentContext.executeQueryAsync(onListCreationSuccess, onListCreationFail);
}
function onListCreationSuccess() {
alert("We've created a list since one doesn't exist yet." );
}
function onListCreationFail(sender, args) {
alert("We didn't create the list. Here's why: " + args.get_message());
}