Run code when tab loads

  • 2
  • Question
  • Updated 2 years ago
  • Answered
  • (Edited)
I have a page where I do not want to use a queue... because I want the user to be able to add to the list of programs on the left. When you click on the calendar icon for a program the list of "program years" for that program displays (using a condition) in the table on the right

the issue is that when the user click on the tab, i would like to run the filter and display the program years for the first program in the list... to do that i need to run a snippet when the tab is clicked on.... is there a skuid way to do that... or do i have to do some sort of jquery thing ?

this is a very generic thing for applications i build... i will need to do it on many, many forms

I can set an ID on the program tab using skuid... but that id is not for the text in the tab itself... but only for the body of the tab... so to get the tab link it looks like I'll have to attach to the onclick of the LI element
Photo of ktyler

ktyler

  • 9,244 Points 5k badge 2x thumb

Posted 5 years ago

  • 2
Photo of ktyler

ktyler

  • 9,244 Points 5k badge 2x thumb
I found another way around this. I put the page title and table for program year in a panel control and gave it an id... then i added some inline css to not display that panel

so when the tab opens nothing shows for program year

then i added a line of javascript to the snippet that runs when you click on the calendar icon for a program change the class of the panel to a class that had display set to block... so when you click on a program... then you can see its program years..... but when the panel opens you don't see anything

the whole goal is to prevent users from adding program years when there is actually no program selected


I'd still like to be able to get at the event when a tab is selected in javascript... the editor component gives me hooks for when models change... something similar for tabs would be great
Photo of ktyler

ktyler

  • 9,244 Points 5k badge 2x thumb
Here's my solution


The tab opens showing nothing for "program years" because the title and table are in a div whose class is set to "display:none"
When you click on a calendar icon in a program row the program years are displayed.
In order to change the header for program years to reflect the program selected I had to use a template... insert a div and then change the content in javascript

var params = arguments[0], row = params.item.row,
   $ = skuid.$;
var program = row.Id;
var program_name = row.Name;
console.log(program + ' ' + program_name);
var program_years = skuid.model.getModel('Cal_Program_Year');
var program_years_condition = program_years.getConditionByName('Cal_Program__c');
//console.log(args.item.row.Id);
program_years.setCondition(program_years_condition,program,true);
console.log('condition set');
skuid.model.updateData([program_years]);
document.getElementById("program_year_panel").className = "program_year_program_selected";
document.getElementById("program_years_title").innerHTML = "Program Years for " + program_name;


here's the inline css



.program_year_no_program_selected { display: none;}
.program_year_program_selected {display: block;}
.custom_title {font-size:18px; font-weight:bold;}


Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
The Tab Set component triggers a tabshow JavaScript event whenever a Tab is selected / activated. Any event handlers bound to the tabshow event are passed a jQuery event object that allows you to know which Tab was selected.

Here is some example code that will spit out the Id of the Tab that was shown (technically the Id of the Tab Panel, not the Tab Nav, but this is). Tabs are given auto-generated Ids by default, but if you give your Tabs Unique Ids, then you could use this to reliably run different code based on the Tab Id that was shown.

This should be added to your Skuid Page as a JavaScript Resource of type Inline (NOT Snippet, NOT Component)

(function(skuid){   
   var $ = skuid.$;
   $(function(){
      $('body').on('tabshow',function(event){
          var tabShown = $(event.target);
          var tabId = tabShown.attr('id');
          console.log(tabId);
      });
   });
})(skuid);

One point to note here: we bound this event generically to the whole document's body element. We could have been more specific, and bound it just to TabSet elements, or to a particular TabSet, for instance one that we gave the Unique Id "Level1Nav". This is a good idea if you have multiple TabSets on the same page and you want to bind separate handlers to each of them.

Here is what this alternate syntax would look like:

$('#Level1Nav').on('tabshow',function(event){
    var tabShown = $(event.target);
    var tabId = tabShown.attr('id');
    console.log('showed a tab in Level1Nav: ' + tabId);
});




Photo of Peter Bender

Peter Bender, Champion

  • 6,246 Points 5k badge 2x thumb
Zach, I have a very similar situation. I need some javascript to run on a page when it loads as an include in a popup. The page functions fine when I run it by it self - the code below runs when the page loads:
$j(document).load
(
    function()
    {
        var models = skuid.model;
        var $ = skuid.$;
        var workshopRow = models.getModel('WorkshopDetail').getFirstRow();
...

However, when I have a popup (from a calendar) that includes this page, the code seems to execute before the models load. I get an error on the getModel() line when I click to load the popup saying that there is no such model yet. How can I modify this to get the code to execute after the included page's models load?
(Edited)
Photo of Zach McElrath

Zach McElrath, Employee

  • 48,984 Points 20k badge 2x thumb
Hi Peter, for your situation, you need to wrap your code in an event handler that gets fired when the Skuid popup finishes loading:

(function(skuid){
var $ = skuid.$;
$(function(){
   $(document.body).one('pageload',function(){
      var models = skuid.model.map();
   });
});
})(skuid);
(Edited)
Photo of Peter Bender

Peter Bender, Champion

  • 6,246 Points 5k badge 2x thumb
Works - thanks!

FYI for readers, this approach (my code below) works when the page is used as an include, but doesn't work when the page is used by itself. For that use my code example above, I guess.
(function(skuid){
var $ = skuid.$;
$(function(){
   $(document.body).one('pageload',function(){
        var models = skuid.model;
        var workshopRow = models.getModel('WorkshopDetail').getFirstRow();
...

(Edited)
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Okay I stand corrected by Ben --- you do NOT want to do what I just said above, as this code is less portable --- it will only work if the page is loaded via a Page Include, but will not work if the page is run on its own.

The best strategy is to not wrap your code in a jQuery ready block at all, but to JUST listen for the 'pageload' event to be fired on the document body. This event will be fired both on initial page load, AND when a Page is loaded via a Page Include.

Be careful though -- check to make sure your code is only getting run when you really want it to.

  • If you just want your code to run the first time that a page is loaded, wrap it in a jQuery ready.
  • If you ONLY want it to be run when a Page Include is loaded, wrap it in a jQuery ready AND a 'pageload' one listener.
  • If you want your code to be run any time that a page is loaded, whether your page is run as a top-level page OR as an included page, then use JUST the 'pageload' one listener method.
See this post for a further explanation:

https://community.skuidify.com/skuid/topics/how_do_i_wait_for_the_dom_to_load_within_a_skuid_page_in...


Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Quick question on the 'tabshow' event: Does it trigger on pageload?
Photo of Zach McElrath

Zach McElrath, Employee

  • 48,984 Points 20k badge 2x thumb
Currently no, the tabshow event is only fired when subsequent tabs are loaded, but not on initial load of the default tab. In the next major release of Skuid, it the tabshow event will be fired for all tab loads, including the load of the default tab. Also, sneak preview, in the next release it will be possible to run a sequence of actions when a tab is first loaded and/or whenever a tab is shown.
(Edited)
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Love it!
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
'tabshow' doesn't seem to be firing on pageload. Can someone confirm that it should be?
Photo of Joseph Ortiz

Joseph Ortiz

  • 594 Points 500 badge 2x thumb
It would be nice. Right now, we have code called twice. Once for page load and once for tabshow.
Photo of Joseph Ortiz

Joseph Ortiz

  • 594 Points 500 badge 2x thumb
So is there anywhere in the documentation that explains all the javascript events we can hook into  events for Skuid components? The use of .on('tabshow') is great but now I'm trying to hook into the events from table filters and table row actions. Is there a .on('tableshow') event?


I'd rather use events to add functionality instead of adding click event handlers for each one.
Photo of Zach McElrath

Zach McElrath, Employee

  • 48,984 Points 20k badge 2x thumb
Joseph, there isn't good documentation yet on all events for all Skuid components -- and there aren't many events you can hook into yet for the Table component. What exactly are you trying to listen for?

- To listen for Table filter changes, the best way would be to use a Model Action so that whenever the Model is re-queried, you can run some actions.
- To listen for clicks on Table Row Actions, you could do a couple of things:
(a) Recomended: Have each Row Action "Run Multiple Actions", and have one of the actions be to "Publish Event" or "Run Skuid JavaScript Snippet" --- this way is recommended if you want to run different logic depending on which Row Action was clicked. If you just want to run generic logic for clicks on any row action in a table, the jQuery approach (b) of binding event listeners would be fine, but otherwise I would do (a) because it's less brittle, it won't break if you rearrange the Row Actions, for instance.
(b) Use jQuery to bind event listeners to clicks on the particular row actions.
Photo of Joseph Ortiz

Joseph Ortiz

  • 594 Points 500 badge 2x thumb
Thanks Zach, I ended up going down the "Run Multiple Actions" approach.
Photo of Charlie Jonas

Charlie Jonas

  • 670 Points 500 badge 2x thumb
This no longer appear to wrok