Dynamically load JS Files from a SharePoint Hosted Add-in into ContentEditor WebPart

Why do we need a dynamically Link to the JS File in the SharePoint Hosted Add-in? There are many reasons for that, i.e. if we update the Add-in, the javascript files are up to date and we do not need to update every contenteditor webpart ever placed. Therefore, it is much better maintainable than paste code into it.

At first the code to place a contenteditor WebPart in a page:

function AddWebPartsToEditForm(hostweburl, serverRelUrl, dfdAddWebParts) {
    var parentCtx = new SP.AppContextSite(clientContext, hostweburl);
    var web = parentCtx.get_web();
    //Javascript Content of the LoadTemplateHubApp.js --> Loads dynamically the jquery and ManipulateEditForm.js lib
    var webPartXml = '__WebPartXml__';    
    serverRelUrlNewFile = serverRelUrl + "/Forms/TemplateHubEditForm.aspx";
    var pageFile = web.getFileByServerRelativeUrl(serverRelUrlNewFile);
    var webPartMgr = pageFile.getLimitedWebPartManager(SP.WebParts.PersonalizationScope.shared);
    var webPartDef = webPartMgr.importWebPart(webPartXml);
    var webPart = webPartDef.get_webPart();
    webPartMgr.addWebPart(webPart, "Main", 2);
    clientContext.load(web);
    clientContext.load(webPart);
    
    clientContext.executeQueryAsync(
        function () { dfdAddWebParts.resolve(); },
        function (data, errorCode, errorMessage) {
            dfdAddWebParts.reject(data, errorCode, errorMessage);
            HideLoadingScreen(loadingScreenElement);
            alert('Error:' + data.responseText);
        }
    );
}

In the sconde one there is the Code to identify the Add-in. This will work with the ProductId of the Add-in, because it is the identifier for Add-in in the SharePoint Environment.

You can load your Javascript files with the function loadjsfile

var ctxCurrent;
var ctxWeb;
var THUrl = '';
 
function loadjsfile(filename){
    var jq = document.createElement('script'); 
    jq.type = 'text/javascript';
    jq.src = filename;
    document.getElementsByTagName('head')[0].appendChild(jq);
}

//get the SharePoint context
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', loadContext);
 
function loadContext() {
    ctxCurrent = new SP.ClientContext.get_current();
    ctxWeb = ctxCurrent.get_web();
    loadTemplateHub();
}
 
function loadTemplateHub() {
    //get the appTiles
    var apps = ctxWeb.getAppInstancesByProductId("1f0f13bd-6f05-4bf4-a555-318074d8738a");
    ctxCurrent.load(apps);
 
    ctxCurrent.executeQueryAsync(
        function onQuerySucceeded(sender, args) {
            if (apps.get_count() > 0) {
                for (var i = 0; i < apps.get_count() ; i++) {                    
                    var app = apps.getItemAtIndex(i); 
                    var appWebUrl = app.get_appWebFullUrl();													
                    loadjsfile(appWebUrl + '/Scripts/jquery-1.9.1.min.js');
                    loadjsfile(appWebUrl + '/Scripts/ManipulateEditForm.js');
                    break;					
                }
				
            }
        },
        function onQueryFailed(sender, args) {
            console.error('getAppTile. Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
        }
    );
}

Now you have to insert the Script to load JS Files into the WebPart. The code should look like this

function AddWebPartsToEditForm(hostweburl, serverRelUrl, dfdAddWebParts) {
    var parentCtx = new SP.AppContextSite(clientContext, hostweburl);
    var web = parentCtx.get_web();
    //Javascript Content of the LoadTemplateHubApp.js --> Loads dynamically the jquery and ManipulateEditForm.js lib
    var webPartXml = '<?xml version="1.0" encoding="utf-8"?>' +
                         '<WebPart xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/WebPart/v2">' +
                          '<Title>TemplateHubRedirect</Title>' +
                          '<FrameType>Default</FrameType>' +
                          '<Description>Manipulates the save button and changes it to a redirection to the WOPI frame.</Description>' +
                          '<IsIncluded>true</IsIncluded>' +
                          '<ZoneID>Main</ZoneID>' +
                          '<PartOrder>0</PartOrder>' +
                          '<FrameState>Normal</FrameState>' +
                          '<Height />' +
                          '<Width />' +
                          '<AllowRemove>true</AllowRemove>' +
                          '<AllowZoneChange>true</AllowZoneChange>' +
                          '<AllowMinimize>true</AllowMinimize>' +
                          '<AllowConnect>true</AllowConnect>' +
                          '<AllowEdit>true</AllowEdit>' +
                          '<AllowHide>true</AllowHide>' +
                          '<IsVisible>false</IsVisible>' +
                          '<DetailLink />' +
                          '<HelpLink />' +
                          '<HelpMode>Modeless</HelpMode>' +
                          '<Dir>Default</Dir>' +
                          '<PartImageSmall />' +
                          '<MissingAssembly>Dieses Webpart kann nicht importiert werden.</MissingAssembly>' +
                          '<PartImageLarge>/_layouts/15/images/mscontl.gif</PartImageLarge>' +
                          '<IsIncludedFilter />' +
                          '<Assembly>Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>' +
                          '<TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName>' +
                          '<ContentLink xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor" />' +
                          '<Content xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor"><![CDATA[' +
                          '<script>' +
                            'var ctxCurrent;' +
                            'var ctxWeb;' +
                            'var THUrl = \'\';' +
                            'function loadjscssfile(filename){' +
                                'var jq = document.createElement(\'script\'); ' +
                                'jq.type = \'text/javascript\';' +
                                'jq.src = filename;' +
                                'jq.async = false;' +
                                'document.getElementsByTagName(\'head\')[0].appendChild(jq);' +
                            '}' +
                            'SP.SOD.executeFunc(\'sp.js\', \'SP.ClientContext\', loadContext);' +
                            'function loadContext() {' +
                                'ctxCurrent = new SP.ClientContext.get_current();' +
                                'ctxWeb = ctxCurrent.get_web();' +
                                'loadTemplateHub();' +
                            '}' +
 
                            'function loadTemplateHub() {' +
                                'var apps = ctxWeb.getAppInstancesByProductId("1f0f13bd-6f05-4bf4-a555-318074d8738a");' +
                                'ctxCurrent.load(apps);' + 
                                'ctxCurrent.executeQueryAsync(' +
                                'function onQuerySucceeded(sender, args) {' +
                                    'if (apps.get_count() > 0) {' +
                                        'for (var i = 0; i < apps.get_count() ; i++) {' +
                                            'var app = apps.getItemAtIndex(i); ' +
                                            'var appWebUrl = app.get_appWebFullUrl();	' +
                                            'loadjscssfile(appWebUrl + \'/Scripts/jquery-1.9.1.min.js\');' +
                                            'loadjscssfile(appWebUrl + \'/Scripts/ManipulateEditForm.js\');' +
                                            'break;' + 
                                        '}' +	
                                    '}' +
                                '},' +
                                'function onQueryFailed(sender, args) {' +
                                    'console.error(\'getAppTile. Request failed. \' + args.get_message() + \'\\n\' + args.get_stackTrace());' +
                                '}' +
                               ');' +
                            '}' +
                          '</script>' +

                          ']]></Content>' +
                          '<PartStorage xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor" />' +
                        '</WebPart>';    
    serverRelUrlNewFile = serverRelUrl + "/Forms/TemplateHubEditForm.aspx";
    var pageFile = web.getFileByServerRelativeUrl(serverRelUrlNewFile);
    var webPartMgr = pageFile.getLimitedWebPartManager(SP.WebParts.PersonalizationScope.shared);
    var webPartDef = webPartMgr.importWebPart(webPartXml);
    var webPart = webPartDef.get_webPart();
    webPartMgr.addWebPart(webPart, "Main", 2);
    clientContext.load(web);
    clientContext.load(webPart);
    
    clientContext.executeQueryAsync(
        function () { dfdAddWebParts.resolve(); },
        function (data, errorCode, errorMessage) {
            dfdAddWebParts.reject(data, errorCode, errorMessage);
            HideLoadingScreen(loadingScreenElement);
            alert('Error:' + data.responseText);
        }
    );
}