1

I am trying to display documents in a web part based off of the parameter passed to the page. However, it seems if i use the following code more than once on a page, it causes all sorts of errors.

Script:

    <html>
<head>
    <script type="text/javascript">
        ExecuteOrDelayUntilScriptLoaded(retrieveListItems, "sp.js");

        function retrieveListItems() {
            var parameter = GetUrlKeyValue('ProjectName'); //get the parameter name, tested and it works

            var clientContext = new SP.ClientContext(); //create client context at this site collection.
            var oList = clientContext.get_web().get_lists().getByTitle('Project Parameters'); //create list object by the title of the, projectParameters is the list to look through
            var camlQuery = new SP.CamlQuery(); //create CAMLquery to pull in list items.
            camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'LinkTitle\'/>' + 
            '<Value Type=\'Computed\'>' + parameter + '</Value></Eq></Where></Query></View>' + 
            '<RowLimit>10</RowLimit></View>'); //define the query, here we pull in the field where the parameter matches. 
            this.collListitem = oList.getItems(camlQuery);//get the items from the list object based on the query defined above.

            clientContext.load(collListitem);//telling the object model to prepare to execute the following object by loading it into the client context.

            clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed)); 
        }
        function onQuerySucceeded(sender, args) {
            var ProjectCharter = '';

            var listItemEnumerator = collListitem.getEnumerator();

            while (listItemEnumerator.moveNext()) {
                var oListItem = listItemEnumerator.get_current();
                ProjectCharter += oListItem.get_item('Project_x0020_Charter');
            };
            var docUrl= ProjectCharter;//set the doclibname to the pulled field
            modIframe(docUrl);
        }

        function onQueryFailed(sender, args) {
            alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
        }
        function modIframe(DocumentLibraryUrl){
            document.getElementById('doclibView').src=DocumentLibraryUrl;
        }

    </script>
</head>
<body>
    <iframe src='' height=600 width=900 id='doclibView'>
    </iframe>
</body>

I have been told not to use the iframe because it isn't a window "inside" of sharepoint, however I am simply trying to display documents stored in a document library, like such: enter image description here

I like the look of the page viewer, and have been told to use it, but I can't figure out how to change the document that loads based off of a parameter. The script I made uses javascript to:

-pull the parameter from the URL

-using the parameter, search a list of URLs for the correct one

-display said URL in an iframe

This works fine and dandy as long as I only want to display one document. As soon as I link a content editor to a second script, I get the following errors: enter image description here

The two lines it is linking to in my scripts are lines 960 and 1074. Since each of the 5 scripts are the same, one would think it would put up a fuss about the same lines in each script. however, the lines it is stopped on are:

960: var listItemEnumerator = collListitem.getEnumerator();

1074: ProjectCharter += oListItem.get_item('Project_x0020_Charter');

Where lines 960 and 1074 are in two separate scripts.

Any idea why Sharepoint would allow me to pull in one iframe, but freaks out if I try more?

Edit: I tried the new info given by ali Jafer. Current Code:

    <html>
<head>
    <script type="text/javascript">
        ExecuteOrDelayUntilScriptLoaded(retrieveListItems, "sp.js");

        function retrieveListItems() {
            var parameter = GetUrlKeyValue('ProjectName'); //get the parameter name

            var clientContext = new SP.ClientContext(); //create client context at this site collection.
            var oList = clientContext.get_web().get_lists().getByTitle('Project Parameters'); //create list object by the title of the, projectParameters is the list to look through
            var camlQuery = new SP.CamlQuery(); //create CAMLquery to pull in list items.
            camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'LinkTitle\'/>' + 
            '<Value Type=\'Computed\'>' + parameter + '</Value></Eq></Where></Query>' + 
            '<RowLimit>10</RowLimit></View>'); //define the query, here we pull in the field where the parameter matches. 
            this.collListitem = oList.getItems(camlQuery);//get the items from the list object based on the query defined above.

            clientContext.load(collListitem);//telling the object model to prepare to execute the following object by loading it into the client context.

            clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));  
        }
        function onQuerySucceeded(sender, args) {
            var ActionPlan = '';

            var listItemEnumerator = collListitem.getEnumerator();

            while (listItemEnumerator.moveNext()) {
                var oListItem = listItemEnumerator.get_current();
                ActionPlan += oListItem.get_item('Action_x0020_Plan');
            };
            var docUrl= ActionPlan;//set the doclibname to the pulled field

            modIframe(docUrl);
        }

        function onQueryFailed(sender, args) {
            alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
        }
        function modIframe(DocumentLibraryUrl){
            var iframe = document.createElement('iframe');
            iframe.src = DocumentLibraryUrl;
            iframe.width = 600;
            iframe.height = 900;
            $('#doclibview').append(iframe);
        }

    </script>
</head>
<body>
    <div id= "doclibview">
    </div>

</body>

This code is still not working when more than one of these are ran on a page, unfortunately.

I am still getting similar errors: enter image description here

These errors only show up when I try to use more than one of these scripts.

The two lines in my code the errors are pointing to, are similar as well:

In the "budget.js" script:

line 913:var listItemEnumerator1 = collListitem.getEnumerator();
line 999:Budget += oListItem1.get_item('Project_x0020_Budget');

Edit 2: The code I am using is the same as above, however, for each of the 5 scripts I changed the name of the div (ie: doclibview1, doclibview2, etc). I put all 5 scripts on the page and the weirdest thing happens. If I visit the page for the first time, it has 1 word document shown under the last tab, "budget".. However, if I refresh the page, the number of page viewers changes: enter image description here

I am not sure how just refreshing the page can change how many of these are shown. Also, how could my code allow up to 4 of the same document to be shown all in the same tab?

Edit 3: Revised code after Nils' help, this got 4 of the 5 tabs working:

   <html>
<head>
    <script type="text/javascript">
        ExecuteOrDelayUntilScriptLoaded(retrieveListItems1, "sp.js");

        var collListitem;
        function retrieveListItems1() {
            var parameter = GetUrlKeyValue('ProjectName'); //get the parameter name, tested and it works

            var clientContext = new SP.ClientContext(); //create client context at this site collection.
            var oList = clientContext.get_web().get_lists().getByTitle('Project Parameters'); //create list object by the title of the, projectParameters is the list to look through
            var camlQuery = new SP.CamlQuery(); //create CAMLquery to pull in list items.
            camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'LinkTitle\'/>' + 
            '<Value Type=\'Computed\'>' + parameter + '</Value></Eq></Where></Query>' + 
            '<RowLimit>10</RowLimit></View>'); //define the query, here we pull in the field where the parameter matches. 
            collListitem = oList.getItems(camlQuery);//get the items from the list object based on the query defined above.

            clientContext.load(collListitem);//telling the object model to prepare to execute the following object by loading it into the client context.

            clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded1), Function.createDelegate(this, this.onQueryFailed1));  
        }
        function onQuerySucceeded1(sender, args) {
            var Field = '';

            var listItemEnumerator = collListitem.getEnumerator();

            while (listItemEnumerator.moveNext()) {
                var oListItem = listItemEnumerator.get_current();
                Field += oListItem.get_item('Budget');
            };
            var docUrl= Field;//set the doclibname to the pulled field

            modIframe1(docUrl);
        }

        function onQueryFailed1(sender, args) {
            alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
        }
        function modIframe1(DocumentLibraryUrl){
            var iframe = document.createElement('iframe');
            iframe.src = DocumentLibraryUrl;
            iframe.width = 600;
            iframe.height = 900;
            $('#doclibview1').append(iframe);
        }

    </script>
</head>
<body>
    <div id= "doclibview1">
    </div>
</body>

I made sure each script has a different named function, but now there is still one error on the same line as before (but only in one script):

var listItemEnumerator = collListitem.getEnumerator();

final edit: Thanks to Nils, I found that the issue was that everything global needs to have a different name (i.e. retrievelistitems--> retrievelistitems1, etc). It still wasn't working after I changed all of the method names, so I did the same to collListitem and it started working!

Final Code:

    <html>
<head>
    <script type="text/javascript">
        ExecuteOrDelayUntilScriptLoaded(retrieveListItems1, "sp.js");

        var collListitem1;
        function retrieveListItems1() {
            var parameter = GetUrlKeyValue('ProjectName'); //get the parameter name, tested and it works

            var clientContext = new SP.ClientContext(); //create client context at this site collection.
            var oList = clientContext.get_web().get_lists().getByTitle('Project Parameters'); //create list object by the title of the, projectParameters is the list to look through
            var camlQuery = new SP.CamlQuery(); //create CAMLquery to pull in list items.
            camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'LinkTitle\'/>' + 
            '<Value Type=\'Computed\'>' + parameter + '</Value></Eq></Where></Query>' + 
            '<RowLimit>10</RowLimit></View>'); //define the query, here we pull in the field where the parameter matches. 
            collListitem1 = oList.getItems(camlQuery);//get the items from the list object based on the query defined above.

            clientContext.load(collListitem1);//telling the object model to prepare to execute the following object by loading it into the client context.

            clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded1), Function.createDelegate(this, this.onQueryFailed1));  
        }
        function onQuerySucceeded1(sender, args) {
            var Field = '';

            var listItemEnumerator = collListitem1.getEnumerator();

            while (listItemEnumerator.moveNext()) {
                var oListItem = listItemEnumerator.get_current();
                Field += oListItem.get_item('Budget');
            };
            var docUrl= Field;//set the doclibname to the pulled field

            modIframe1(docUrl);
        }

        function onQueryFailed1(sender, args) {
            alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
        }
        function modIframe1(DocumentLibraryUrl){
            var iframe = document.createElement('iframe');
            iframe.src = DocumentLibraryUrl;
            iframe.width = 600;
            iframe.height = 900;
            $('#doclibview1').append(iframe);
        }

    </script>
</head>
<body>
    <div id= "doclibview1">
    </div>
</body>

2 Answers 2

1
+50

You're JavaScript is all in global scope.

If you copy the JavaScript multiple times in one page, you still will have only one function retrieveListItems, onQuerySucceeded, onQueryFailed and modIframe. Not to mention this.collListitem, which you override in evey call of retrieveListItems.

Try adding some scope: Check this article on scope and IIFE.

3
  • I truly appreciate it, got it to work! Commented Oct 20, 2016 at 17:00
  • Well, not as done as i thought, only 3 of the tabs are working, I am still getting the "collection has not been initialized" error Commented Oct 20, 2016 at 17:07
  • you "load" this.collListItem in retieveListItems() but access collListItems (without this) in onQuerySuccseed - those two might not be the same.
    – Nils
    Commented Oct 20, 2016 at 21:22
2

Your camel is messed up.

<View><Query><Where><Eq><FieldRef Name=\'LinkTitle\'/>' + 
            '<Value Type=\'Computed\'>' + parameter + '</Value></Eq></Where></Query></View>' + 
            '<RowLimit>10</RowLimit></View>'

should be:

<View><Query><Where><Eq><FieldRef Name=\'LinkTitle\'/>' + 
            '<Value Type=\'Computed\'>' + parameter + '</Value></Eq></Where></Query>' + 
            '<RowLimit>10</RowLimit></View>'

You were closing the view too early and then closing it off again at the end. Should be at the end only.

The above should work! Whoever said that iframe shouldn't be used is wrong! Sharepoint Online is riddled with iframes, it's iframes galore. Also if you drill down to the HTML generated by the page viewer webpart it's an iframe.

Also note that this is not dynamic code! So you can't run two content editor webparts unless the HTML ids are different and the JS code reflects that. By this I mean:

<iframe src='' height=600 width=900 id='doclibView'>

that can only be used once due to the id and your JS code is looking for that id. Do it through JS instead like

function modIframe(DocumentLibraryUrl){

   var iframe = document.createElement('iframe');
   iframe.src = DocumentLibraryUrl;
   $("#dynamicIframes").append(iframe);

}

The above IDs for iframe should be auto generated.

Your HTML should be:

<body>
   <div id="dynamicIframes">
   </div>
</body>

We are appending a new iframe each time your JS code is called.

<script type="text/javascript">
    ExecuteOrDelayUntilScriptLoaded(retrieveListItems, "sp.js");

    var collListitem;
    function retrieveListItems() {
        var parameter = GetUrlKeyValue('ProjectName'); //get the parameter name

        var clientContext = new SP.ClientContext(); //create client context at this site collection.
        var oList = clientContext.get_web().get_lists().getByTitle('Project Parameters'); //create list object by the title of the, projectParameters is the list to look through
        var camlQuery = new SP.CamlQuery(); //create CAMLquery to pull in list items.
        camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'LinkTitle\'/>' + 
        '<Value Type=\'Computed\'>' + parameter + '</Value></Eq></Where></Query>' + 
        '<RowLimit>10</RowLimit></View>'); //define the query, here we pull in the field where the parameter matches. 
        collListitem = oList.getItems(camlQuery);//get the items from the list object based on the query defined above.

        clientContext.load(collListitem);//telling the object model to prepare to execute the following object by loading it into the client context.

        clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));  
    }
    function onQuerySucceeded(sender, args) {
        var ActionPlan = '';

        var listItemEnumerator = collListitem.getEnumerator();

        while (listItemEnumerator.moveNext()) {
            var oListItem = listItemEnumerator.get_current();
            ActionPlan += oListItem.get_item('Action_x0020_Plan');
        };
        var docUrl= ActionPlan;//set the doclibname to the pulled field

        modIframe(docUrl);
    }

    function onQueryFailed(sender, args) {
        alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
    }
    function modIframe(DocumentLibraryUrl){
        var iframe = document.createElement('iframe');
        iframe.src = DocumentLibraryUrl;
        iframe.width = 600;
        iframe.height = 900;
        $('#doclibview').append(iframe);
    }

</script>

I don't know if I'm understanding you correct or what you're trying to do. You state why is it returning the same document several times:

    function onQuerySucceeded1(sender, args) {
        var Field = '';

        var listItemEnumerator = collListitem.getEnumerator();

        while (listItemEnumerator.moveNext()) {
            var oListItem = listItemEnumerator.get_current();
            Field += oListItem.get_item('Budget');
        };
        var docUrl= Field;//set the doclibname to the pulled field

        modIframe1(docUrl);
    }

change to

    function onQuerySucceeded1(sender, args) {
        var Field = '';

        var listItemEnumerator = collListitem.getEnumerator();

        while (listItemEnumerator.moveNext()) {
            var oListItem = listItemEnumerator.get_current();
            Field += oListItem.get_item('Budget');

             modIframe1(Field);
        };

    }

What I understand from above, you're looping through and constantly setting "Budget" into the "Field" variable. What is "Budget" field, what does it contain? Is it a full URL?

So you're pulling the parameter from URL. Say its value is 2. You pass that into the query and you want it to return the budget? I presume it's URLs for the iframes. If so the updated code segment should work. Your code was always collating all Budget rows into the variable and creating an iframe with that variable every time.

4
  • While this works, and I am going to use your way of doing it... This doesn't solve the underlying issue unfortunately Commented Oct 18, 2016 at 16:46
  • just updated the answer. I looked at your update and looked at your code again. noticed that you had this.collListitem when it should be only collListitem and set it to a global variable.
    – Ali Jafer
    Commented Oct 19, 2016 at 8:17
  • I also tried and tested that Commented Oct 20, 2016 at 6:32
  • updated my answer
    – Ali Jafer
    Commented Oct 21, 2016 at 9:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.