4

I'm having the function which is wait for sync after that it will load the content. Below function is working perfectly in firefox but not working in IE11

//Working in other browser and inserting the multiple records but not in IE

async function setup()
{
    await Word.run(async(context)=> {

        for (var i=0; i < 5; i++)
        {
            var controler = context.document.contentControls.getByTag("myTag"+i);
            controler.load();
            await context.sync();
            controler.items[0].insertPargraph("Adding paragraph "+i);
        }
    }
    )};

}

For IE11, below function is working perfectly for inserting only one record

//Working in IE for the only one record
function setUp()
{
    Word.run(function (context){

        var selectedTag = context.document.contentControls.getByTag("myTag");
        context.load(selectedTag,'text');
        return context.sync().then(function()
        {
            controler.items[0].insertPargraph("Adding paragraph 0")
        });

    })
}

Now problem is I want to iterate the loop for the contents, I have written the return function inside the forloop that the reason it is not working

//Below function is not working
function setUp()
{
    Word.run(function (context){

        for (var i=0; i < 5; i++)
        {
            var selectedTag = context.document.contentControls.getByTag("myTag");
            context.load(selectedTag,'text');
            return context.sync().then(function()
            {
                controler.items[0].insertPargraph("Adding paragraph 0")
            });
        }
    })
}

How to write the await function for IE11 browsers. I have tried the goto Lable function but that also not working.

mkHun
  • 5,891
  • 8
  • 38
  • 85
  • 1
    Looks like you forgot `getByTag("myTag"+i);` and `insertPargraph("Adding paragraph "+i)` in third example. The **+i** part – Moti Korets Apr 05 '18 at 08:07

2 Answers2

2

Your async version uses i with getTag and when adding the paragraph, but your subsequent code example doesn't. It matters for the solution.

Common Ground

You can create a promise chain, similar to my answer here but different enough it might be hard to apply that to your case. Basically, you start with a resolved promise (p), then use p = p.then(...) to build the chain.

If you don't need to use i's value

...then you can do it like this:

function setUp()
{
    Word.run(function (context){
        var p = Promise.resolve();
        for (var i = 0; i < 5; i++)
        {
            p = p.then(function() {
                var selectedTag = context.document.contentControls.getByTag("myTag");
                context.load(selectedTag,'text');
                return context.sync().then(function()
                {
                    controler.items[0].insertPargraph("Adding paragraph 0")
                });
            });
        }
    })
}

If you do need to use i's value

...then we need to bake it into the code since you have to use var (IE11 has let, but it doesn't have ES2015 semantics for for loops):

function setUp()
{
    Word.run(function (context){
        function doOne(index) {
            // We use `index` below
            var selectedTag = context.document.contentControls.getByTag("myTag" + index);
            context.load(selectedTag,'text');
            return context.sync().then(function()
            {
                controler.items[0].insertPargraph("Adding paragraph " + index)
            });
        }
        var p = Promise.resolve();
        for (var i = 0; i < 5; i++)
        {
            p = p.then(doOne.bind(null, i));
        }
    })
}

Giving setUp a return value

Your async version assumes that Word.run returns a promise and that it expects its callback to return a promise. I can't find any documentation to support that, but then, the web documentation for this stuff appears to be truly amazingly bad.

If both of those assumptions are true, then to haev setUp return a promise, we'd only need to make small changes: return before Word.run and return p; at the end of the callback (see *** comments);

function setUp()
{
    return Word.run(function (context){                      // ***
        function doOne(index) {
            // We use `index` below
            var selectedTag = context.document.contentControls.getByTag("myTag" + index);
            context.load(selectedTag,'text');
            return context.sync().then(function()
            {
                controler.items[0].insertPargraph("Adding paragraph " + index)
            });
        }
        var p = Promise.resolve();
        for (var i = 0; i < 5; i++)
        {
            p = p.then(doOne.bind(null, i));
        }
        return p;                                            // ***
    })
}

But if Word.run doesn't return a promise, or doesn't expect a promise from its callback, that won't work and we have to create our own:

function setUp()
{
    return new Promise(function(resolve, reject) {           // ***
        Word.run(function (context) {
            function doOne(index) {
                // We use `index` below
                var selectedTag = context.document.contentControls.getByTag("myTag" + index);
                context.load(selectedTag,'text');
                return context.sync().then(function()
                {
                    controler.items[0].insertPargraph("Adding paragraph " + index)
                });
            }
            var p = Promise.resolve();
            for (var i = 0; i < 5; i++)
            {
                p = p.then(doOne.bind(null, i));
            }
            p.then(resolve).catch(reject);                   // ***
        })
    });
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • If `setUp` is meant to be an `async` function, shouldn't it return a promise that is resolved only when all the internal promises have been resolved? Something like `return Promise.all(innerArrayOfPromises);` – Terry Apr 05 '18 at 08:18
  • @Terry: **If** `Word.run` returns a promise (Microsoft's documentation is so bad I can't tell if it does), then the `async` version does wait for it. I can't find any indication it does, but I'll update just in case. We wouldn't want `Promise.all`, no. – T.J. Crowder Apr 05 '18 at 08:27
  • @T.J.Crowder I have tried your code it is working for the till fourth loop, for the fifth loop it is throwing `ReferenceError: 'resolve' is undefined` error – mkHun Apr 05 '18 at 14:51
  • @mkHun: I take it you mean you've tried to use the last example. All due respect, you must have copied it incorrectly, as `resolve` is definitely in-scope and not `undefined` in the code above. – T.J. Crowder Apr 05 '18 at 15:10
2

I think what you are trying to achieve is to chain the sync() calls together so that the callback in Word.run only resolves when everything is syncd. You can do this using Promise.all() to generate a promise resolving when all provided promises have resolved.

function setUp() {
  Word.run(function(context) {
    const promises = [];
    for (var i = 0; i < 5; i++) {
      var selectedTag = context.document.contentControls.getByTag("myTag");
      context.load(selectedTag, 'text');
      let p = context.sync().then(function() {
        controler.items[0].insertPargraph("Adding paragraph 0")
      });
      promises.push(p);
    }
    return Promise.all(promises);
  })
}
Sebastian Speitel
  • 7,166
  • 2
  • 19
  • 38
  • Technically speaking, since `promises` is never reassigned, you can safely use `const promises`... ;) same thing for `p` and `selectedTag`. – Terry Apr 05 '18 at 08:23