I'm initiating an email create, by calling the code below, and adding an attachment to it.
I want the user to be able to type in the receipient, and modify the contents of the message, so I'm not sending it immediately.
Why do I get a RangeError the 2nd time the method is called?
(The first time it works correctly.)
function NewMailItem(p_recipient, p_subject, p_body, p_file, p_attachmentname)
{
try
{
var objO = new ActiveXObject('Outlook.Application');
var objNS = objO.GetNameSpace('MAPI');
var mItm = objO.CreateItem(0);
mItm.Display();
if (p_recipient.length > 0)
{
mItm.To = p_recipient;
}
mItm.Subject = p_subject;
if (p_file.length > 0)
{
var mAts = mItm.Attachments;
mAts.add(p_file, 1, p_body.length + 1, p_attachmentname);
}
mItm.Body = p_body;
mItm.GetInspector.WindowState = 2;
} catch(e)
{
alert('unable to create new mail item');
}
}
The error is occuring on the mAts.add line. So when it tries to attach the document, it fails.
Also the file name (p_file) is a http address to a image.
Won't work outside of IE, the user needs to have Outlook on the machine and an account configured on it. Are you sure you want to send an email this way?
I'm trying it with this little snippet, and it works flawlessly:
var objO = new ActiveXObject('Outlook.Application');
var mItm = objO.CreateItem(0);
var mAts = mItm.Attachments;
var p_file = [
"http://stackoverflow.com/content/img/vote-arrow-up.png",
"http://stackoverflow.com/content/img/vote-arrow-down.png"
];
for (var i = 0; i < p_file.length; i++) {
mAts.add(p_file[i]);
}
Note that I left off all optional arguments to Attachments.Add(). The method defaults to adding the attachments at the end, which is what you seem to want anyway.
Can you try this standalone snippet? If it works for you, please do a step-by-step reduction of your code towards this absolute minimum, and you will find what causes the error.
first do mItm.display()
then write mItm.GetInspector.WindowState = 2;
this will work
Related
I've been able to sort out the middle bit (the API seems to be called to just fine) along with the submenu displaying. Originally I thought that just the end part wasn't working but I'm now thinking that the selection part isn't either.
What am I doing wrong with the getSelection() and what do I need to do to insert a link into said selection? (to clarify, not to replace the text with a link, but to insert a link into the text)
//Open trigger to get menu
function onOpen(e) {
DocumentApp.getUi().createAddonMenu()
.addItem('Scry', 'serumVisions')
.addToUi();
}
//Installation trigger
function onInstall(e) {
onOpen(e);
}
//I'm not sure if I need to do this but in case; declare var elements first
var elements
// Get selected text (not working)
function getSelectedText() {
const selection = DocumentApp.getActiveDocument().getSelection();
if (selection) {
var elements = selection.getRangeElements();
Logger.log(elements);
} else {
var elements = "Lack of selection"
Logger.log("Lack of selection");
}
}
//Test run
// insert here
// Search Function
function searchFunction(nameTag) {
// API call + inserted Value
let URL = "https://api.scryfall.com/cards/named?exact=" + nameTag;
// Grabbing response
let response = UrlFetchApp.fetch(URL, {muteHttpExceptions: true});
let json = response.getContentText();
// Translation
let data = JSON.parse(json);
// Jackpot
let link = data.scryfall_uri;
// Output
Logger.log(link);
}
// Test run
searchFunction("Lightning Bolt");
//Let's hope this works how I think it works
function serumVisions() {
const hostText = getSelectedText();
const linkage = searchFunction(hostText);
// Unsure what class I'm supposed to use, this doesn't
const insertLink = DocumentApp.getActiveDocument().getSelection().newRichTextValue()
.setLinkUrl(linkage);
Logger.log(linkage);
}
For the first part, I tried the getSelection() and getCursor() examples from the Google documentation but they don't seem to work, they all just keep returning null.
For the inserting link bit, I read all those classes from the Spreadsheet section of the documentation, at the time I was unaware but now knowing, I haven't been able to find a version of the same task for Google Docs. Maybe it works but I'm writing it wrong as well, idk.
Modification points:
In your script, the functions of getSelectedText() and searchFunction(nameTag) return no values. I think that this might be the reason for your current issue of they all just keep returning null..
elements of var elements = selection.getRangeElements(); is not text data.
DocumentApp.getActiveDocument().getSelection() has no method of newRichTextValue().
In the case of searchFunction("Lightning Bolt");, when the script is run, this function is always run. Please be careful about this.
When these points are reflected in your script, how about the following modification?
Modified script:
Please remove searchFunction("Lightning Bolt");. And, in this case, var elements is not used. Please be careful about this.
From your script, I guessed that in your situation, you might have wanted to run serumVisions(). And also, I thought that you might have wanted to run the individual function. So, I modified your script as follows.
function getSelectedText() {
const selection = DocumentApp.getActiveDocument().getSelection();
var text = "";
if (selection) {
text = selection.getRangeElements()[0].getElement().asText().getText().trim();
Logger.log(text);
} else {
text = "Lack of selection"
Logger.log("Lack of selection");
}
return text;
}
function searchFunction(nameTag) {
let URL = "https://api.scryfall.com/cards/named?exact=" + encodeURIComponent(nameTag);
let response = UrlFetchApp.fetch(URL, { muteHttpExceptions: true });
let json = response.getContentText();
let data = JSON.parse(json);
let link = data.scryfall_uri;
Logger.log(link);
return link;
}
// Please run this function.
function serumVisions() {
const hostText = getSelectedText();
const linkage = searchFunction(hostText);
if (linkage) {
Logger.log(linkage);
DocumentApp.getActiveDocument().getSelection().getRangeElements()[0].getElement().asText().editAsText().setLinkUrl(linkage);
}
}
When you select the text of "Lightning Bolt" in the Google Document and run the function serumVisions(), the text of Lightning Bolt is retrieved, and the URL like https://scryfall.com/card/2x2/117/lightning-bolt?utm_source=api is retrieved. And, this link is set to the selected text of "Lightning Bolt".
Reference:
getSelection()
I'm teaching myself app-script, and created a simple function to delete a row if there was an error. Here is the code:
//GLOBALS
var SS = SpreadsheetApp.openById("the_sheet_ID"); //just a placeholder because I didn't want to post the real ID
var SHEET = SS.getSheetByName("300x250");
var RANGE = SHEET.getDataRange();
var DELETE_VAL = "#N/A";
var COL_TO_SEARCH = 2; // The column to search for the DELETE_VAL (Zero is first)
function deleteEachRow(){
var rangeVals = RANGE.getValues();
//Reverse the 'for' loop.
for(var i = rangeVals.length-1; i >= 0; i--){
if(rangeVals[i][COL_TO_SEARCH] === DELETE_VAL){
SHEET.deleteRow(i+1);
};
};
};
I have been receiving e-mails from app script telling me a server error occurred. Below is a copy of the e-mail:
Your script, Deleting_Rows, has recently failed to finish
successfully. A summary of the failure(s) is shown below. To configure
the triggers for this script, or change your setting for receiving
future failure notifications, click here.
4/16/20 1:27 AM deleteEachRow We're sorry, a server error occurred.
Please wait a bit and try again. time-based 4/16/20 1:27 AM
Sincerely,
Google Apps Script
The function is timed to run every minute, so it usually fixes itself. I've seen this issue for triggers from deleted functions, or for the broken click here link, but my function is not deleted, and the link works. I haven't been able to find any information about what is causing the error, how to fix it, if the error has to do with my code or google's servers. Any information or insight anyone has would be super helpful!
As it's an sporadic server error, you could workaround it by catching the error with a try/catch statement and, in case there's an error, retry to execute the code after waiting a bit with sleep function, the code would look this:
function deleteEachRow(){
var i= 0;
while(i < 3) {
try {
//GLOBALS
var SS = SpreadsheetApp.openById("1e-JtL0KacshxjWMRSIwwCzHeg0oj7OtzIw_-m_VV8HQ"); //just a placeholder because I didn't want to post the real ID
var SHEET = SS.getSheetByName("300x250");
var RANGE = SHEET.getDataRange();
var DELETE_VAL = "#N/A";
var COL_TO_SEARCH = 2; // The column to search for the DELETE_VAL (Zero is first)
var rangeVals = RANGE.getValues();
//Reverse the 'for' loop.
for(var i = rangeVals.length-1; i >= 0; i--){
if(rangeVals[i][COL_TO_SEARCH] === DELETE_VAL){
SHEET.deleteRow(i+1);
};
};
// If it gets here, there were no errors
break;
}
catch(e) {
sleep(5000);
i++;
}
}
};
I am using Meteor, which uses Mongodb as its database. I have code that inserts several documents into a collection when users fill out a form. When these documents are inserted, I would like to fire some JavaScript code within the server side directories that sorts through the collection in question for documents with matching fields as the documents just inserted.
My problem is that I do not know how to fire code on the server when the new documents arrive. Would it make sense to Meteor.call a Meteor.method at the end of the code involved with inserting, with the Meteor.method called preforming the sorting code I need?
Edit:
As you can see, in the below code I'm not calling any Meteor methods as none exist yet. The vast majority of this code is simply lead up for the insert({}) at the end of the page, so I think it can be safely ignored. The only server side code I have is to declare the possibleGames mongo collection.
I am not sure what you mean by call a plain JavaScript function, my problem is getting any code firing at all.
possibleGames = new Mongo.Collection("possibleGames");
Template.meet_form.events({
"submit .meet_form": function(event, template){
event.preventDefault();
var user = Meteor.userId();
var where = event.target.where.value;
var checkedGames = [];
function gameCheck (game) {
if (game.checked === true){
checkedGames.push(game.value);
};
};
var checkedDays = [];
function dayCheck (day) {
if (day.checked === true){
checkedDays.push(day.value);
};
};
console.log(event.target.where.value)
gameCheck(event.target.dnd);
gameCheck(event.target.savageWorlds);
gameCheck(event.target.shadowRun);
console.log(checkedGames);
dayCheck(event.target.monday);
dayCheck(event.target.tuesday);
dayCheck(event.target.wednesday);
dayCheck(event.target.thursday);
dayCheck(event.target.friday);
dayCheck(event.target.saturday);
dayCheck(event.target.sunday);
console.log(checkedDays);
var whereWhat = [];
for (i = 0; i < checkedGames.length; i++) {
var prepareWhereWhat = where.concat(checkedGames[i]);
whereWhat.push(prepareWhereWhat);
};
console.log(whereWhat);
var whereWhatWhen = [];
for (a = 0; a < whereWhat.length; a++) {
var prepareWWW1 = whereWhat[a];
for (b = 0; b < checkedDays.length; b++) {
var prepareWWW2 = prepareWWW1.concat(checkedDays[b]);
whereWhatWhen.push(prepareWWW2);
};
};
console.log(whereWhatWhen);
for (i = 0; i < whereWhatWhen.length; i++) {
possibleGames.insert({
game: whereWhatWhen[i],
user: user,
created_on: new Date().getTime()
})
}
}
});
You don't need to do a meteor.call on the server because you're already on the server.
Just call a plain javascript function.
If what you want to call from your first Meteor.method is already in another Meteor.method, then refactor that function to extract out the common bit.
Some code would also help if this is still confusing.
I'm trying to send a message to my custom receiver for ChromeCast. I use the following code in my Android app to send a code to the receiver;
Cast.CastApi.sendMessage(mApiClient, "urn:x-cast:move", "TEST");
On the receiving side I have the following code;
window.mediaElement = document.getElementById('media');
window.mediaManager = new cast.receiver.MediaManager(window.mediaElement);
window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
window.castReceiverManager.start();
window.castReceiverManager.onSenderConnected = function(event) {
//This is called
}
window.customMessageBus = window.castReceiverManager.getCastMessageBus('urn:x-cast:move', cast.receiver.CastMessageBus.MessageType.STRING);
var defaultFunction = window.customMessageBus.onMessage;
window.customMessageBus.onMessage = function(event) {
//This is not called
defaultFunction(event);
};
As I pointed out in the code, the 'onSenderConnected' is called, so I know it connected to the app. But when I try to send a message over the custom messagebus, it doesnt give me anything. I'm completely new to android and cast, so I could be doing a thousand things wrong. Can anybody help me solve this?
I solved it myself. What I did wrong was starting the castReceiverManager before adding the custom namespace. So the correct code for the receiver compared to what I posted in the question would be;
window.mediaElement = document.getElementById('media');
window.mediaManager = new cast.receiver.MediaManager(window.mediaElement);
window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
//Removed the start here
window.castReceiverManager.onSenderConnected = function(event) {
//OnConnect
}
window.customMessageBus = window.castReceiverManager.getCastMessageBus('urn:x-cast:move', cast.receiver.CastMessageBus.MessageType.STRING);
var defaultFunction = window.customMessageBus.onMessage;
window.customMessageBus.onMessage = function(event) {
//OnMessage
defaultFunction(event);
};
//Start at the end
window.castReceiverManager.start();
yeah, so can i do that?
i have a program already written that has two functions.. and one is recursive..
so i want to know how can i execute just one line of code at a time by pressing a button..
i hope it's possible
and also i'm doing this in a web page
this is my script.. it has no importance but just for you to make an idea..
READ THIS... i don't want to debug it with firebug or whatever... i want to make this myself inside my program... i want to make the code execute 1 line at a time when i press a button..so basically im building my own debugger.. the graphical part is already done.. i only need to know how to do this..
function nod(){
var info;
var st;
var dr;
}
function help(){
var rad;
}
var h = new help();
h.rad = new nod();
h.rad = null;
function create(h,x)
{
if(h.rad==null)
{
h.rad = new nod();
h.rad.info = x ;
h.rad.st = h.rad.dr = null;
}
else{
if(x < h.rad.info){
var h1;
h1 = new help();
h1.rad = h.rad.st;
create(h1,x);
h.rad.st = h1.rad;
}
else{
var h2;
h2 = new help();
h2.rad = h.rad.dr;
create(h2,x);
h.rad.dr = h2.rad;
}
}
}
function read(h)
{
var input = [0,10,2,1,8,9,4,5,3,6,20,11,30,21,31,22,23,
];
var i;
for(i=1;i<=16;i++)
{
create(h,input[i]);
}
}
read(h);
Open your site in Chrome and use the integrated script debugger to execute the script step by step after a breakpoint you set.
But have at least a quick look at the whole box of tools I linked too to ensure you know what you can expect and use the best tool for your need.