cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
matt5834
Community Participant

Javascript to Advance to Next Module Item

Hi - 

What might be the javascript/API call to have a button in an embed advance to the next module. 

I plan on hiding Canvas Next Previous buttons and have the external page button advance the module. 


Thank you!
Matt

#javascript

Labels (1)
Tags (1)
4 Replies
James
Community Champion

matt5834,

The simple (but probably wrong) answer is that you set window.top.location to the place you want to go to. This works in Chrome, I didn't test it in other browsers. Assuming that you know where you want to go, that may be all that's involved.

But the reason I said it's probably wrong is that it's a bit more complicated than most people think and you may end up reconsidering your decision. I think you mean "inside an iframe" when you say "embedding". If not, please clarify as it may (or may not) change things.

The iframe provides a sandbox or separation between the contents of the parent window and the iframe contents. If they are loaded from the same origin (when talking about security this includes the hostname), then the parent window and iframe can generally access each other. However, if they are from different origins, then access is extremely limited. See Same-origin policy - Web security | MDN for more information.

This means that unless your page is hosted within your Canvas instance (custom JavaScript at the account level), you're not going to be able to see the elements on the parent window (Canvas) to know what the next and previous buttons are or where they head to.

Lest people jump on my case about the ability to embed JavaScript in files and serve them up from within Canvas, that is true. However, they get dished up from a different origin than the page itself, so they are subject to the same-origin policy and the script can't access the contents of the parent window to see what the location should be.

If I try to access the location (without using a try {} catch {} block) of the next/previous buttons in the parent window , I get this in Chrome:

Blocked a frame with origin "https://cluster1-files.instructure.com" from accessing a cross-origin frame

The cluster-1-files is where the files are stored for our instance. But it's not where the contents of the page come from, so it considers it cross-origin and won't let the iframe (embed) access the content page within Canvas -- except for those few items listed on the page I linked to.

That means that your application will need to know what the next and previous buttons are pointing at. This could be done by maintaining your own list or by using the API to get it from Canvas To use the API, you'll need the appropriate permissions of a user. Since those buttons can change based on the user and mastery paths and other factors, you would need to recreate the logic used by Canvas to determine what is next and previous for the appropriate user.

As if that wasn't enough, to get rid of the next/previous buttons, you would also need to use custom JavaScript, which must be set at the account or subaccount level and can't be done at a course or LTI level. Those are (partially) there for consistency for the users and if you're navigating within Canvas, then you should use Canvas to do it, not an embedded application. Navigation links/buttons within the app should navigate within the app.

Now that I've given some of the problems, let me provide you with a possible solution -- depending on what kind of permissions you have with your Canvas instance.

If you have Canvas Admin rights so that you can install custom JavaScript on a site, then one way to work around the issue is to use window.postMessage. You use the custom JavaScript to install a listener in the parent window (Canvas) that listens for a message from the iframe (embed). It can then return information back -- which could be the next and previous buttons and where they head.  That code could also hide the next and previous buttons. I would send a message from the iframe to the parent window when it loads to say "Hey, I'm going to provide my own navigation, you should disable yours" and use it to get the locations of what the navigation should be.

Realize though, that if you have an embed inside an iframe that comes from a different origin, that it won't have access to the CSS of the parent window either, which means that the buttons won't look like the normal Canvas navigation buttons.

Even if you mean LTI instead of iframe, you run into similar issues.

wurzel
Community Participant

Hi Matt,

You should be able to just grab the link to the desired module then use this piece of html to link to that:

<a class="btn btn-primary" href="yourlinkhere" role="button">Your Button Text Here</a>

Just sub in the link to the module in the href value. Note that this might not by copy safe, so you might have to update these when you copy to another semester.

matt5834
Community Participant

Thanks Scott! The issue I'm having (and why I thought I might need to access the API) is that I need to have the same button go to the same module that exists in different courses. 

If I understand you correctly, your answer would have the  button link to a module in one specific course. Is that right?

Thank  you!
Best, 
Matt

James
Community Champion

If you're making this an LTI, you can pass information about the course in with the launch. This includes the Canvas.moduleItem.id if you use custom variables

With the courseID and moduleItemID, you can then use the Modules API to fetch the next and previous links. Use the Get module item sequence endpoint with asset_type=ModuleItem (literally) and asset_id=moduleItemID (replace with number). This is detailed in another response I wrote a couple of days ago: Getting the Module ID from Module Item ID. Chicken vs Egg...