~[wc:commonscripts]
~[wc:admin_header_css] ~[text:psx.html.admin_reports.runreports.start_page] > PowerSchool Customization ~[wc:admin_navigation_css] ~[SetPostValue:tab=js]

# PowerSchool Customization

~[x:insertfile;tabs.html]

### JavaScript

JavaScript is a programming language that runs in web browsers and makes web pages dynamic and interactive.

Script Tags
JavaScript is embedded within script tags in an HTML document.
`<script type="text/javascript"> JavaScript code here. </script>` Script tags may also reference external JavaScript files.
`<script type="text/javascript" src="myJsFile.js"></script>`
Comments
Adding comments helps to clarify JavaScript code. `// Use two slashes for single line commenting /** Use a slash and two asterisks for multi-line commenting **/`
Primitive Data Types
Number `1005 45.75` String - Can be enclosed in single or double quotes `"Hello World" 'JavaScript is awesome!'` Boolean - only two possible values `true false`
Variables
Variables are defined using the var key word.
Variables can be defined and immediately assigned a value (let x = 5;)
If a variable is defined and not assigned a value, it has a value of undefined (let y;) `// Define a variable and leave it undefined var varName; // Define a variable and assign it a value var number1 = 1; var number2 = 3; var sum = number1 + number2; var stringVariable = 'Hello'; stringVariable = 'Goodbye' // reassign the value of stringVariable`
Let
let is an alternative to the var key word and functions slightly differently `// create a variable using let and assign a value let grade_level = 5; // this is okay with var var name = "John"; var name = "Fred"; // variable "name" is recreated with a new value // this is NOT okay with let let name = "John"; let name = "Fred"; // results in a JavaScript error. Name has already been defined` It may seem less desirable to use let as it is more likely to result in JS errors. However let can be useful to protect developers against logic errors in their code.
In larger projects, we may forget that we've used a variable name elsewhere in our application. Reusing a variable name can unintentionally cause needed values to be overwritten.
Const
const defines a constant value. The value is assigned when created and cannot be changed `// create a constant and assign a value const userName = "Carl"; userName = "Jim"; // results in a JavaScript error` const can be used to prevent unintended changes to a value either by other code in an application or by then end-user.
String Templates
Strings in JS can be surrounded by single-quotes, double-quotes, or back-tics (`).
A string surrounded by back-tics is a String Template. A String Template allows us to use variable substitution in our strings. `let firstName = 'John'; let lastName = 'Doe'; //With a regular JS string let greeting = "Hello " + firstName + " " + lastName + "!"; //With a String Template let greeting = `Hello ${firstName} ${lastName}!`;`
Operators
Arithmetic Operators

(+ ) Addition

(- ) Subtraction

(* ) Multiplication

(/ ) Division

`5 + 6 9 - 2 12 / 6 6 * 4 (5 - 3) * 5` Assignment and Concatenation

(= ) Assignment Operator

(+ ) Concatenate Values (when not numeric)

`let x = 12; let name = 'John' + ' ' + 'Doe';`
Displaying Information with JavaScript

- InnerHTML - Set the HTML contents of an element
- alert() - Generate an alert message
- console.log() - Log information to the web console

`document.getElementById('student').innerHTML = 'John Doe'; alert('JavaScript alert message'); console.log('JavaScript console message');`
Finding elements in the document
document.querySelector()
The querySelector method finds elements in the document using css selectors `//Find the first <p> element document.querySelector('p'); //Find the first element with class="name" document.querySelector('.name'); //Find the element with id="grade" document.querySelector('#grade'); //set the innerHTML property of a matched element document.querySelector('#demo').innerHTML = "This is my demo element";` document.querySelectorAll()
The querySelectorAll method finds all matching elements in the document using css selectors `//Find all <p> elements document.querySelectorAll('p'); //Find all elements with class="name" document.querySelectorAll('.name');`
Conditional Logic
Use an if/else statement to conditionally execute code
The else condition is optional `if(grade_level > 8){ console.log('High School'); }else{ console.log('Not High School'); }`
Comparison Operators

(== ) Equality

(=== ) Strict Equality - Value and Type

(!= ) Inequality

(!== ) Strict Inequality

(> ) Greater Than

(>= ) Greater Than or Equal

( < ) Less Than

( <= ) Less Than or Equal

`//Equality vs. Strict Equality '5' == 5 //true '5' === 5 //false - values match but not type`
Ternary Operator
variablename = (condition) ? value1:value2; `let status = enroll_satus == 0 ? 'active' : 'not active'; //Same as above but longer if(enroll_status == 0){ let status = 'active'; }else{ let status = 'not active'; }`
Logical Operators

( && ) And

(|| ) Or

( ! ) Not

`if(grade_level > 8 && gender == 'M'){ console.log('Eighth Grade Male'); } if(grade_level == 6 || grade_level == 7 || grade_level == 8){ console.log('Middle School Student'); } if(!booleanVariable){ console.log('boolean value is false'); }`
Functions
Functions are blocks of code that perform operations and or return values.
Functions can accept parameters.
Functions are executed when they are called (invoked).
A function that performs operations `function changeName(){ document.getElementById('name').innerHTML = 'Jane Doe'; } changeName(); //invoke the changeName function` A function that returns a value `function addNumbers(a,b){ let result = a + b; return result; } addNumbers(1,2); //invoke the function let x = addNumbers(1,2); //invoke the function and set the result as the value of a variable (x) console.log(addNumbers(1,2)); //invoke the function and log the result`
Arrow Functions
Arrow functions provide a more concise way to define a function. The following is an example of the adNumbers function from the previous example rewritten as an arrow function. `addNumbers = (a,b) => a + b;` Note that there is no return keyword in the function. If our function contains only one statement, that result will automatically be returned.
If the function contains multiple statements, they will be wrapped in brackets, and the return keyword is required to return a value.
Functions and Variable Scope
A variable's scope defines where that variable can be accessed within an application. Variables can have two types of scope.

- Global - Accessible anywhere in the application
- Local(function) - Accessible only within the function in which they are declared

`let name = "Jeff"; //Global scope function myFunction(){ let age = 41; //Local scope //code here can CAN access name and age } //code here CAN access name, but CAN NOT access age` Visit W3Schools for a more detailed explanation of variable scope.
Scope works slightly differently with let and const. Check out THIS article to learn more about let and const scopes.
Complex Data Types
Arrays are collections of values in a comma, separated list.
Arrays are denoted by square brackets. `//create an array and assign its value to the variable courses let courses = ["Math","Language Arts","Science"]; //Arrays use a zero-based indexing system courses[0]; //Retrieves the value at index 0: Math courses[2] = "Art"; //Changes the value at index 2 from Science to Art //the indexOf() method returns the index of an element (-1 if not found) courses.indexOf("Language Arts"); // returns 1 //the includes() method determines if the array contains a value courses.includes("Algebra"); // returns false courses.includes("Math"); // returns true //Arrays have a length property courses.length; //returns 3 //add an element to the end of the array using the push() method courses.push("Social Studies"); //remove the last element from the array using the pop() method courses.pop(); //retrieve array contents as a string using the toString() method console.log(courses.toString()); // Logs "Math,Language Arts,Science" //get an array from a delimited string using the split() method console.log("Jim-Samantha-Bobby".split('-')); // Logs ["Jim","Samantha","Bobby"]` Unlike some other languages, arrays are not strongly typed in JavaScript. An array can contain primitive and complex data types or a combination of different data types.
Objects have multiple properties (a.k.a keys). Each property has a value.
Sample student object. `//Create an object and assign it as the value of a variable (student) let student = { "last_name":"Jones", "first_name":"Angela", "dob":"10/12/2002", "grade_level":11 }; //Object properties can be referenced using dot notation console.log(student.dob); //Log the dob property of the student object student.grade_level = 12; //Change the value of the grade_level property student.gender = 'M'; //Create a property (gender) on the student object and set the value to 'M' //Object properties can also be referenced using bracket notation console.log(student['dob']); student['grade_level'] = 12; student['gender'] = 'M'; //if a property name is stored in a variable, bracket notation is required let myProperty = 'grade_level'; student.myProperty; // this returns undefined student[myProperty]; // this returns 11` Property values can also be other complex types (arrays, objects, functions) `let student = { "last_name":"McCallister", "first_name":"Kevin", "activities":["Baseball","Soccer","Chess Club"], "guardian":{ "last_name":"McCallister" "first_name":"Kate", "email":"kmccallister@gmail.com" } } console.log(student.activities[0]); //Log the first activity in the student's activities array console.log(student.guardian.email); //Log the email property of the student's guardian object`
Loops
for() loop `//Loop through the numbers 1 - 10 and log them to the console for (let i = 1; i <= 10; i++){ console.log(i); }` forEach() `let nums = [2,4,7,9]; //iterate through each number in the nums array and log the square nums.forEach(function(curNum){ console.log(curNum * curNum); });` Iterating through an object `let grades = { "Q1":"A-", "Q2":"B", "Q3":"B+", "Q4":"A-" }; //iterate through each key(property) of the grades object and display the data //in the line below Object.keys(grades) gets an array of keys from the grades object - ["Q1", "Q2", "Q3", "Q4"] Object.keys(grades).forEach(function(key) { console.log(key + 'Grade: ' + grades[key]); }); // for/in is an alternate way to iterate over properties of an object for(storecode in grades) console.log(grade + 'Grade: ' + grades[storecode]); });`
Event Listeners
Event listeners facilitate the execution of code when an event has occurred (e.g. a button has been clicked or the value of an input has changed) `// alert user when they have clicked a button document.getElementById("myBtn").addEventListener("click", alertClick); function alertClick(){ alert("You have fired a click event"); } // alert user when they have changed an input, select, or textarea document.getElementById("myInput").addEventListener("change", alertChange); function alertChange(){ alert("You have fired a change event"); } //an event argument is automatically padded to the event listener function document.getElementById("myForm").addEventListener("submit", validateForm); function validateForm(event){ //code to validate form inputs if(!valid){ event.preventDefault(); //prevents form submission } }` Commonly Used Events

Event | Description
--- | ---
blur | Occurs when an element loses focus
change | Occurs when the content of a form element, the selection, or the checked state have changed (for <input>, <select>, and <textarea>)
click | Occurs when the user clicks on an element
dblclick | Occurs when the user double-clicks on an element
focus | Occurs when an element gets focus
keyup | Occurs when the user releases a key
mouseover | Occurs when the pointer is moved onto an element, or onto one of its children
submit | Occurs when a form is submitted

Checking Form Element Status
Use the following element properties to check the values of form elements `//For text, select, and textarea elements, use the value property document.querySelector('#myInput').value //Use the checked property to determine if a checkbox or radio button is checked document.querySelector('#myCheckbox').checked //returns true or false`
try/catch
try/catch allows developers to avoid JS errors interrupting code processing `try{ myFunction(); }catch(error){ console.log("There was an error running the code. Please contact support. Error: " + error); }`
setTimeout()
The setTimeout function waits for a specified number of milliseconds to execute code `setTimeout(function(){ console.log("it has now been three seconds") }, 3000);`
Promises
In JavaScript, a Promise is an object that represents the eventual completion (or failure) of an operation and its resulting value. `let foodOrder = new Promise((resolve, reject) => { setTimeout(function(){ let isRestaurantOpen = true; if (isRestaurantOpen) { resolve('Order Placed!'); } else { reject('Sorry, the restaurant is closed.'); } }, 3000); }); foodOrder .then(message => console.log(message)) // Output: 'Order Placed!' .catch(error => console.error(error)); // Output if rejected` A Promise can be in one of three states:

- Pending: The initial state, where the operation hasn't completed yet.
- Fulfilled: The operation completed successfully.
- Rejected: The operation failed.

fetch (AJAX)
The JS fetch method is used to load data from an external resource. `fetch('someFile.json').then(function(res) { return res.json(); }).then(function(data){ console.log(data) }); // Shorter version using arrow functions fetch('someFile.json').then(res => res.json()).then(data => console.log(data));` The above example retrieves JSON.
If retrieving plain text, use res.text() on the second line.
If retrieving an image, use res.blob().
The JavaScript Engine

Memory Heap The place (memory) where objects are stored when we define variables. Call Stack Keeps track processes in a script that calls multiple functions — what function is currently being run and what functions are called from within that function Web APIs Supports complex operations and data access. Callback Queue Functions added to the queue are processed in a first-in-first-out order. When the Call Stack is empty, functions in the queue are processed. Event Loop Monitors the Call Stack and the Callback Queue. If the Call Stack is empty, the Event Loop will take the first event from the queue and will push it to the Call Stack. |

### jQuery

What is jQuery
jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API that works across a multitude of browsers. With a combination of versatility and extensibility, jQuery has changed the way that millions of people write JavaScript. The jQuery library is part of the core PowerSchool distribution.
To leverage the power of the jQuery library, include the common scripts wildcard in your custom pages.
Writing jQuery Code
jQuery functions are called in PowerSchool JavaScript by using `$j` `$j(selector).function();`
jQuery Selectors
jQuery selectors provide a means to select elements in an HTML document. The most commonly used selectors are id selectors and class selectors.

- Select element by ID - `$j('#elementID')`

- The id selector will operate on a single element. No two elements in a document should be given the same id.

- Select element by class - `$j('.className')`

- The class selector can operate on a single element or multiple elements with the same class attribute.

Selector | Example | Selects
--- | --- | ---
#id | `$j("#lastname")` | The element with id="lastname"
.class | `$j(".intro")` | All elements with class="intro"
.class,.class | `$j(".intro,.demo")` | All elements with the class "intro" or "demo"
element | `$j("p")` | All <p> elements
el1,el2,el3 | `$j("h1,div,p")` | All <h1>, <div> and <p> elements
parent descendant | `$j("div p")` | All <p> elements that are descendants of a <div> element
.first() | `$j("p").first()` | The first <p> element
.last() | `$j("p").last()` | The last <p> element
.even() | `$j("tr").even()` | All even <tr> elements
.odd() | `$j("tr").odd()` | All odd <tr> elements
.eq(index) | `$j("ul li").eq(3)` | The fourth element in a list (index starts at 0), negative numbers count from the end (-1 is last element)
.slice(index) | `$j("ul li").slice(3)` | List elements with an index greater than 3
.slice(0, index) | `$j("ul li").slice(0, 3)` | List elements with an index less than 3
.not(selector) | `$j("input").not(":empty")` | All input elements that are not empty
:contains(text) | `$j(":contains('Hello')")` | All elements which contains the text "Hello"
:hidden | `$j("p:hidden")` | All hidden <p> elements
:visible | `$j("table:visible")` | All visible tables
[attribute] | `$j("[href]")` | All elements with a href attribute
[attribute=value] | `$j("[href='default.htm']")` | All elements with a href attribute value equal to "default.htm"
[attribute^=value] | `$j("[title^='Tom']")` | All elements with a title attribute value starting with "Tom"
[attribute*=value] | `$j("[title*='hello']")` | All elements with a title attribute value containing the word "hello"
:checkbox | `$j(":checkbox")` | All input elements with type="checkbox"
:checked | `$j(":checked")` | All checked input elements

`<div id="selectorTestDiv"> <div id="testDiv"> <h3>Div (id="testDiv")</h3> <span>Span 1</span> <span>Span 2</span> <span>Span 3</span> <span class="specialSpan">Span 4 (class="specialSpan")</span> <span class="specialSpan">Span 5 (class="specialSpan")</span> </div> <span> A span not contained in the testDiv. </span> <table> <tr><th>Col 1</th><th>Col 2</th><th>Col 2</th></tr> <tr><td>1:1</td><td>1:2</td><td>1:3</td></tr> <tr><td>2:1</td><td>2:2</td><td>2:3</td></tr> <tr><td>3:1</td><td>3:2</td><td>3:3</td></tr> <tr><td>4:1</td><td>4:2</td><td>4:3</td></tr> </table> </div>`
Use the text box below to test your jQuery selector skills.
$j(' ')

### Div (id="testDiv")

Span 1 Span 2 Span 3 Span 4 (class="specialSpan") Span 5 (class="specialSpan")
A span not contained in the testDiv.

Col 1 | Col 2 | Col 2
--- | --- | ---
1:1 | 1:2 | 1:3
2:1 | 2:2 | 2:3
3:1 | 3:2 | 3:3
4:1 | 4:2 | 4:3

Useful jQuery Functions
`$j(function () {});` - Define code that should run when the page has completed loading. `//Generate an alert when the page is finished loading $j(function () { alert('ready'); });` `.val()` - Retrieve or set the value of an input. `//log the value of an element where id="gender" console.log($j('#gender').val()); //set the value of an element where id="gender" $j('#gender').val('F');` `.html()` - Retrieve or set the innerHTML of an element. `//set the value of a variable to the contents of an element where id="studentName" let name = $j('#studentName').html(); //set the contents of an element where id = "studentName" $j('#studentName').html('John Doe');` `.show()` and `.hide()` - Show or hide an element. `//hide any element with class="conditional" $j('.conditional').hide(); //show any element with class="conditional" $j('.conditional').show();` `.on('click', function() {})` - Known as an event listener. Run JavaScript when an element has been clicked
A function must be defined as a parameter for the event listener. `//show elements with a class="additionalInfo" when a target button has been clicked $j('#showInfoBtn').on('click', function(){ $j('.additionalInfo').show(); });` `.on('change', function() {})` - Event listener for the change of an input value `//alert the user to enter a last name if the field is emptied $j('#last_name').on('change', function(){ if($j('#last_name').val() == ''){ alert('Please enter a last name'); } });` `.before()`, `.after()`, `.prepend()`, `.append()` - Insert content relative to a DOM element. `//assume we have the following element in our DOM //<div id="targetElement">Original Div Contents</div> //before() places content before a matching element $j('#targetElement').before('Content Before'); //Result - Content Before<div id="targetElement">Original Div Contents</div> //prepend() places content inside a matching element before the current contents $j('#targetElement').prepend('Prepended Content '); //Result - <div id="targetElement">Prepended Content Original Div Contents</div> //append() places content inside a matching element after the current contents $j('#targetElement').append(' Appended Content'); //Result - <div id="targetElement">Original Div Contents Appended Content</div> //after() places content after a matching element $j('#targetElement').after('Content After'); //Result - <div id="targetElement">Original Div Contents</div>Content After` `.clone()` - Create a copy of an element in the DOM. `//duplicate a div by cloning it and inserting it into the DOM let newDiv = $j('.myDiv').clone(); $j('.myDiv').after(newDiv);` `.remove()` - Remove content from the DOM. `//remove the last row from a table $j('#myTable tr').last().remove();` `.empty()` - Remove all child elements of a selected element. `//remove all rows from a table $j('#myTable').empty();` `.on()` - Add event listeners for elements that may not yet exist when the DOM is ready
Often times, there is a need to add event listeners to elements that have been added to the DOM after the document has been loaded. `$j('body').on('click','.targetElementClass', function(){ //handle click event });` `.attr()` - Get or set an attribute for an element `<div id="statusDiv" data-status="current">Div Contents</div>` `//Log the data-status attribute of an element console.log($j('#statusDiv').attr('data-status')); //Set the data-status attribute of an element $j('#statusDiv').attr('data-status','expired')` `.each()` - jQuery forEach Loop `//Array of student objects let students = [{"name":"Sally Juarez","grade":5},{"name":"Elise Marks","grade":7}]; //Loop through values in the students array, and log each value $j(students).each(function(){ //The current value is referred to in the loop using the "this" keyword console.log(this); }); //Loop through rows in a table, and log the contents of the first td $j('#myTable tr').each(function(){ //In this case, wrap the "this" keyword in $j() so jQuery functions can follow console.log($j(this).find('td').first().html()); });`

- "I'm listening for a change." |
| Make me disappear.
| I was hiding.

## Finding DOM Elements

Method | Description | Example
--- | --- | ---
.closest() | Get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree | `$j('#myTd').closest('tr)`
.find() | Get the elements which are descendants of the selected element matching a provided selector | `$j('#myTr').find('td')`
.siblings() | Get the siblings of an element | `$j('#myLi').siblings('li')`
.next() | Get the immediately following sibling of an element | `$j('#myLi').next('li')`
.prev() | Get the immediately preceding sibling of an element | `$j('#myLi').prev('li')`

## Dialogs

A dialog is a floating window that contains a title bar and a content area. The dialog window can be moved, resized and closed with the 'x' icon by default.
$j('#target').dialog({modal: true/false, title: 'Dialog Title', width: ###});

- modal - if modal, other content on page cannot be interacted with while dialog is open
- title - dialog title
- width - width in px

`<div style="display:none"> <div id="myDialogDiv"> <form> <table> <tr> <td>First Name</td> <td><input type="text" name="[students]first_name" /></td> </tr> <tr> <td>Last Name</td> <td><input type="text" name="[students]last_name" /></td> </tr> </table> </form> </div> </div> <button id="newStudentBtn">New Student</button> <script type="text/javascript"> $j('#newStudentBtn').on('click', function () { $j('#myDialogDiv').dialog({ modal: true, title: 'New Student', width: 500 }); }); </script>`

First Name |
Last Name |

## More Advanced Functions / AJAX

Function | Description | Example | Code Explained
.load(url) | Load contents from another page (url) into a target container. | `$j('#containerId').load('anotherPage.html',function(){ alert('loaded'); }):` | Load the contents of anotherPage.html into an element with an id of "containerId". Once the content has been loaded, alert the user.
.serialize() | Encode a set of form elements as a string for submission. | `let formData = $j('#myForm').serialize();` | Store string representation of data from a form with an id of "myForm" into a variable named formData.
.post(url, data, callback function) | Load data from the server using a HTTP POST request. url - A string containing the URL to which the request is sent. data - Data that is sent to the server with the request (often a serialized form). callback function - function run when the request has completed successfully. | `$j.post('otherPage.html', $j('#myForm').serialize(),function(data){ alert(data); });` | Submit the data in a form with an id of "myform" to otherPage.html. After receiving a response from otherPage.html, display an alert with the response text.
.getJSON(url, data, callback function) | Retrieve JSON data. | `$j.getJSON('otherPage.json', {"param1":"p1Value","param2":"p2Value"},function(data){ let myJson = data; });` | Retrieve JSON data from the server passing parameters to the resource. After receiving the response, from otherPage.json, set the response value to a variable (myJsonVar)

## jQuery Deferred

jQuerry Deferred objects allow developers to execute code when one or more processes have completed `let studentsRetrieved = $j.Deferred(); let gradesRetrieved = $j.Deferred(); let students; let grades; $j.post('studentInfo.json' ,function(studentData){ students = studentData; studentsRetrieved.resolve(); }); $j.post('gradeInfo.json' ,function(gradeData){ grades = gradeData; gradesRetrieved.resolve(); }); //The following will not execute until students and grades have been retrieved (i.e. the studentsRetrieved and gradesRetrieved Deferreds have been resolved $j.when(studentsRetrieved, gradesRetrieved).then(function(){ //Integrate the grades data with the student data });`

### Helpful PS Functions

## Loading Dialogs

When retrieving, writing, or processing data that requires time, it can be useful to prompt the user to wait for processing to finish.
Use the loadingDialog() and closeLoading() `<button id="testLoading">Test Loading Dialog</button> <script type="text/javascript"> $j('#testLoading').on('click', function(){ loadingDialog(); setTimeout(function(){ //wait 2 seconds and close closeLoading(); }, 2000); }); </script>`

## Loading Dialogs - Titles and Percent Complete

Use setLoadingDialogTitle() to set the title of a loading dialog. Use updateLoadingDialogPercentComplete() to show progress. `<button id="pctCompleteBtn">Show Progress</button> <script type="text/javascript"> $j('#pctCompleteBtn').on('click', function(){ loadingDialog(); recordsProcessed = 0; processRecord(); }); let totalRecs = 10; let recordsProcessed = 0; function processRecord(){ setLoadingDialogTitle(recordsProcessed + ' of ' + totalRecs); //Get an integer between 1 and 100 number let pct = Math.round((recordsProcessed/totalRecs)*100); updateLoadingDialogPercentComplete(pct); setTimeout(function(){ if(++recordsProcessed == totalRecs){ closeLoading(); }else{ processRecord(); } }, 300); } </script>`

## psAlert()

psAlert() is similar to the JavaScript alert, but it is styled to look better in PS `<button id="alertBtn">Alert</button> <script type="text/javascript"> $j('#alertBtn').on('click', function(){ psAlert({message:'Thank you for clicking the alert button',title:'Button Clicked'}); }); </script>`

## psConfirm()

psConfirm() provides the opportunity for a user to confirm or cancel an action `<button id="deleteBtn">Delete</button> <script type="text/javascript"> $j('#deleteBtn').on('click', function(){ psConfirm({ title:"Confirm Delete", message:"Not really going to delete anything... just an example.", oktext:"Confirm", canceltext:"Cancel", ok: function(){ alert('Okay'); } }); }); </script>`

## initBehaviors()

The PS initBehaviors() function initializes standard PS behaviors such as calendar picker functionality for inputs with class="psDateWidget".
This is helpful when content is loaded into the page after PS widget initialization has occurred. `<div id="widgetDiv"></div> <button id="newDtWidgetBtn">Add Date Widget</button> <button id="initBtn">Run initBehaviors()</button> <script type="text/javascript"> $j('#newDtWidgetBtn').on('click', function(){ $j('#widgetDiv').append('<input type="text" class="psDateWidget" />'); }); $j('#initBtn').on('click', function(){ initBehaviors(); }); </script>`

### Angular JS

Angular JS is a JavaScript framework that manages a process called data-binding.
This allows developers to change data in JavaScript and have the user interface automatically reflect these changes.
The Angular JS framework allows developers to structure code in a way that makes the code more flexible, maintainable, and reusable.

## Setting Up A Page To Use Angular JS

`<script type="text/javascript"> //Require the Angular JS framework on the page require(['angular','components/shared/index'], function (angular) {

//Create an application (demoApp) and store it in a variable (myApp)

let myApp = angular.module('demoApp', ['powerSchoolModule']);

//Create a controller (demoAppCtrl) to house the application logic

myApp.controller('demoAppCtrl', function($scope) { //Application logic here }); }); </script> <div data-require-path="components/shared/index" data-module-name="myApp" data-bootstrap-local="true" ng-controller="demoAppCtrl"> <!-- This is the View --> </div>`

## Terminology

- Module - An Angular JS application
- Controller - A container for the application logic (JavaScript) for part of our page
- View - The user interface - the HTML
- $scope - A link provided by Angular JS between the controller and the view.

## Data-binding

Data-binding refers to the automatic synchronization of data between the model and the view. `<script type="text/javascript"> require(['angular','components/shared/index'], function (angular) { let myApp = angular.module('demoApp', ['powerSchoolModule']); myApp.controller('demoAppCtrl', function($scope) { $scope.userName = "Fred"; }); }); </script> <body> <div data-require-path="components/shared/index" data-module-name="demoApp" data-bootstrap-local="true" ng-controller="demoAppCtrl"> <input type="text" ng-model="userName" /> <div>{{userName}}</div> <div ng-bind="userName"></div> </div> </body>`
{{userName}}
Change the value in the text box above to watch data-binding in action.

## Directives

Angular JS directives are attributes that can be added to HTML elements.
A number of built-in directives allow developers to add functionality applications.

- ng-model - Bind the value of an input to a value in the controller
- ng-bind - Bind the contents of an element to a value in the controller
- ng-repeat - Repeat an element for each value in a collection in the controller
- ng-show - Show an element when a condition is met
- ng-hide - Hide an element when a condition is met
- ng-if - Create an element when a condition is met
- ng-disabled - Disable an input if a condition is met
- ng-click - Execute a command when an element click event occurs
- ng-change - Execute a command when an input change event occurs

View `<div> <input ng-model="newStudent.name" placeholder="Name" /> <input ng-model="newStudent.grade_level" placeholder="Grade Level"> <button ng-click="addStudent()" ng-disabled="invalidNew()">Add Student</button> </div> <div> Grade Filter <input ng-model="selectedGrade" placeholder="Blank For Any" /> </div> <table> <tr> <th>Name</th> <th>Grade Level</th> </tr> <tr ng-repeat="student in students" ng-show="showStudent(student)"> <td>{{student.name}}</td> <td>{{student.grade_level}}</td> </tr> </table>` Controller `myApp.controller('demoAppCtrl', function($scope) { //initialize $scope properties $scope.newStudent = {}; $scope.selectedGrade = ''; $scope.students = [ {"name":"James","grade_level":'8'}, {"name":"Susan","grade_level":'11'} ]; //Add the newStudent object to the students array and reset the newStudent value to an empty object $scope.addStudent = function(){ $scope.students.push($scope.newStudent); $scope.newStudent = {}; }; //Determine if the newStudent object is invalid (blank name or invalid grade level) $scope.invalidNew = function(){ if($scope.newStudent.name == ''){ return true; } let grade = Number($scope.newStudent.grade_level); if(grade > -5 && grade < 13){ return false }else{ return true; } }; //Determine if a student should be visible based on the selected grade $scope.showStudent = function(student){ return ($scope.selectedGrade == '' || student.grade_level == $scope.selectedGrade); }; });`
Grade Filter

Name | Grade Level
--- | ---
{{student.name}} | {{student.grade_level}}

## Custom Directives

Developers can also define their own custom directives for use in applications.
These custom directives can be very useful for creating re-usable code.
studentTemplate.html - An html file that will hold the HTML template for our directive `<div style="display:inline-block;width:20em;border:1px solid black" class="center"> <H2 style="background-color:silver;margin:0px"> {{student.name}} </H2> Grade {{student.grade_level}} </div>` The custom directive - The Angular JS code to create a directive named studentTile `myApp.directive("studentTile", function (){ return { scope: {student: "="}, templateUrl: "studentTemplate.html" } });` The scope property allows us to provide a student object to each instance of our directive.
The templateUrl sets the contents for the directive
The view - We called the directive studentTile (camel cased). To refer to this directive in the view, we convert this to a hyphenated format (student-tile). `<H3>Students</H3> <span ng-repeat="stu in students"> <student-tile student="stu"></student-tile> </span>` A student object is passed to the directive as an attribute.

### Students

## HTTP (AJAX)

Angular JS's $http service allows developers to easily execute AJAX calls `

//This controller will depend upon the Angular JS $http service. //$http is added to the controller function parameters. This is called dependency injection.

myApp.controller('demoAppCtrl', function($scope, $http) { $http({ "url": "someUrl", "method": "GET or POST", "params": "parameters for GET (object)", "data": "data for POST (object)" }).then(function successCallback(response){

//code to run if request succeeds

}, function errorCallback(response){

//code to run if request fails

}); });` studentCount.html `~[tlist_sql; SELECT count(*) FROM students WHERE grade_level = ~(gpv.grade) ;]~(total)[/tlist_sql]` View `Select a grade level to find the student total <select ng-model="grade_level" ng-change="getGradeCount()"> <option value="0">0</option> <option value="1">1</option> ... </select> <b>{{gradeCount}}</b> <span ng-if="gradeCount"> Students in Grade {{grade_level}}</span>` Controller `$scope.getGradeCount = function(){ $http({ "url": "studentCount.html", "method": "GET", "params": {"grade":$scope.grade_level} }) .then(function(response){ $scope.gradeCount = response.data; }); };`
Select a grade level to find the student total
{{gradeCount}} Students in Grade {{grade_level}}

## Filters

Angular JS filters are used to transform data.
Filters are added using the pipe character(|)
`$scope.userName = "Fred"; $scope.numericValue = 15587.58886; $scope.courses = [ {"name":"Biology","department":"Sci"}, {"name":"Algebra","department":"Mat"}, {"name":"Trigonometry","department":"Mat"}, {"name":"Literature","department":"Eng"} ];` `No Filter - {{userName}} <br/> lowercase - {{userName | lowercase}} <br/> uppercase - {{userName | uppercase}}<br/> No Filter - {{numericValue}} <br/> number : 1 - {{numericValue | number : 1}} <br/> currency - {{numericValue | currency}}<br/><br/> <p>ng-repeat="course in courses | orderBy:'name' "</p> <table> <tr><th>course</th><th>Department</th></tr> <tr ng-repeat="course in courses | orderBy:'name'"> <td>{{course.name}}</td> <td>{{course.department}}</td> </tr> </table> <p>ng-repeat="course in courses | filter:courseSearch"</p> <div class="center"><input ng-model="courseSearch" placeholder="course Search"/></div> <table> <tr><th>course</th><th>Department</th></tr> <tr ng-repeat="course in courses | filter:courseSearch"> <td>{{course.name}}</td> <td>{{course.department}}</td> </tr> </table>`
No Filter - {{userName}}
lowercase - {{userName | lowercase}}
uppercase - {{userName | uppercase}}
No Filter - {{numericValue}}
number : 1 - {{numericValue | number : 1}}
currency - {{numericValue | currency}}

ng-repeat="course in courses | orderBy:'name' "

course | Department
--- | ---
{{course.name}} | {{course.department}}

ng-repeat="course in courses | filter:courseSearch"

course | Department
--- | ---
{{course.name}} | {{course.department}}

## Custom Services

gradeService.js `define(['angular'], function(angular) { let myApp = angular.module('gradeModule', []); myApp.service('gradeService', function(){ this.getStudentGradeLevelName = function(student){ if(Number(student.grade_level) < 6){ return "Elementary"; }else if(Number(student.grade_level) < 9){ return "Middle"; }else if(Number(student.grade_level) < 13){ return "High"; }else if(Number(student.grade_level) == 99){ return "Graduated"; }else{ return "Unknown"; } } }); });` Module/Controller `Must include the path to the service so it can be included in the module require(['angular','components/shared/index','/path_to_file.../gradeService.js'], function (angular) { //Include the name of the desired module in the application dependencies let myApp = angular.module('demoApp', ['powerSchoolModule','gradeModule']); //Include the gradeService as a dependency for the controller myApp.controller('demoAppCtrl', function($scope, gradeService) { $scope.honorRollStudents = [ {"name":"Ben Johnson","grade_level":"12"}, {"name":"Louise Wilcox","grade_level":"1"}, {"name":"Renly Inman","grade_level":"4"}, {"name":"Alissa Smith","grade_level":"10"}, {"name":"Lena Gardner","grade_level":"7"}, {"name":"Lester Millis","grade_level":"99"}, {"name":"Alfred Caleston","grade_level":"20"} ]; $scope.gradeName = function(student){ //Because we've included the gradeService return gradeService.getStudentGradeLevelName(student); }; }); });` View `<table> <tr><th>Student</th><th>Grade Level</th><th>Grade Desc</th></tr> <tr ng-repeat="student in honorRollStudents"> <td>{{student.name}}</td> <td>{{student.grade_level}}</td> <td>{{gradeName(student)}}</td> </tr> </table>`

Student | Grade Level | Grade Desc
--- | --- | ---
{{student.name}} | {{student.grade_level}} | {{gradeName(student)}}

## Sample Service for PowerQuery Execution

pqService.js `define(['angular'], function(angular) { angular.module("powerQueryModule",[]) .service("pqService",function($http, $q){ //query - the name of the PowerQuery //data - JavaScript Object including any parameters that must be passed to the query this.getPQResults = function(query, data){ let deferredResponse = $q.defer(); $http({ url: '/ws/schema/query/' + query, method:'POST', data: data || {}, params: {"pagesize":0}, headers: { 'Accept': 'application/json', "Content-Type": "application/json" } }) .then(function(response){ deferredResponse.resolve(response.data.record || []); }); return deferredResponse.promise; }; }); });` Put the service to use `require(['angular','components/shared/index','/path_to_file.../pqService.js'], function (angular) { let myApp = angular.module('demoApp', ['powerSchoolModule','powerQueryModule']); myApp.controller('demoAppCtrl', function($scope, $http, pqService) { pqService.getPQResults('com.mba.psugDemo.schoolData.enrollment').then(function(response){ //Response will be an array of results //View the console to see an example }); }); });` A Note About the $q Service

The example above relies on the AngularJS $q service.
The $q service facilitates the return of a value from a function that contains asynchronous code.

`//Make the $q service available to our pq service .service("pqService",function($http, $q){ //Create a new deferred object which will be resolved once our asynchronous process has completed let deferredResponse = $q.defer(); //Resolve our deferred object with the result of the AJAX call deferredResponse.resolve(response.data.record || []); //The once the deferred response has been resolved, this line will return the value passed to the resolve() function return deferredResponse.promise;`

Using this architecture allows code to call the function and use a .then() function to work with the returned value.

## $q Example

The following example is a refactored demonstration of the jQuery Deferred example above.
This code will function in the same way as the jQuery example using the AngularJS framework. `let studentsRetrieved = $q.defer(); let gradesRetrieved = $q.defer(); let students; let grades; $http({ "url": "studentInfo.json", "method": "GET"}).then(function(res){ students = res.data; studentsRetrieved.resolve(); }); $http({ "url": "gradeInfo.json", "method": "GET"}).then(function(res){ grades = res.data; studentsRetrieved.resolve(); }); //The following will not execute until students and grades have been retrieved (i.e. studentsRetrieved and gradesRetrieved have been resolved $q.all([studentsRetrieved.promise,gradesRetrieved.promise]).then(function(){ //Integrate the grades data with the student data });`
~[x:insertfile;footer.html] ~[wc:admin_footer_css]