I am trying to do a login form by using JSON, I have 3 different users to login in a single login page, they are as 1. User 2. Admin 3. Supplier
This is my code. I am doing this as a test case, I will change the authentication details to server side later on.
<html>
<head>
<title> Login Form</title>
<script>
function validate()
{
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
var loginlist = { "User": {
"userlist":[{"username":"usr1", "password":"a123"},{"username":"usr2", "password":"a123"},{"username":"usr3", "password":"a123"}],
"ID":1
},
"Admin": {
"adminlist":[{"username":"admin1", "password":"b123"},{"username":"admin2", "password":"b123"},{"username":"admin3", "password":"b123"}],
"ID":2
},
"Supplier": {
"supplierlist":[{"username":"sup1", "password":"c123"},{"username":"sup2", "password":"c123"},{"username":"sup3", "password":"c123"}],
"ID":1
}
};
var logged = false;
if(loginlist[0].User.ID === 1){
for(var i =0; i < loginlist[0].User.userlist.length; i++){
if(username == loginlist[0].User.userlist[i].username && password == loginlist[0].User.userlist[i].password){
logged= true;
}
}
if(logged)
alert("User login");
else
alert("User login fail");
}
else if(loginlist[0].Admin.ID === 2){
for(var j =0; j < loginlist[0].Admin.adminlist.length; j++){
if(username == loginlist[0].Admin.adminlist[j].username && password == loginlist[0].Admin.adminlist[j].password){
logged= true;
}
}
if(logged)
alert("Admin login");
else
alert("admin login fail");
}
else{
for(var k =0; k < loginlist[0].Supplier.supplierlist.length; k++){
if(username == loginlist[0].Supplier.supplierlist[k].username && password == loginlist[0].Supplier.supplierlist[k].password){
logged= true;
}
}
if(logged)
alert("Supplier login");
else
alert("supplier login fail");
}
}
</script>
</head>
<body>
<div class="container">
<div class="main">
<h2>Login Form</h2>
<form id="form_id" method="post" name="myform">
<label>User Name :</label>
<input type="text" placeholder="Enter username" name="username" id="username"/>
<label>Password :</label>
<input type="password" placeholder="Enter Password" name="password" id="password"/>
<input type="button" value="Login" id="submit" onclick="validate()"/>
</form>
</body>
</html>
which I have tried. My issue is when I enter something into the username and password nothing is displaying, I have done this kind of program but with the single user operation. I am not able to achieve this multiple users in a single login page
I am not quite sure what is the reason for having each individual user type as separate arrays, it might be good for some specific use case, but it will certainly be more straightforward to have all users in a single set.
Having everything in one array and then providing some functions to use to fetch a specific user type would be a better approach, as this way you don't need to worry about the result so much from the beginning. Besides you should always be working with as much raw material as possible; though people might find this arguable.
It is usually better to not trigger JavaScript code in the <head> tag of the HTML unless it is needed, as the code is executed before all of the document is loaded. It is usually safer to put all JavaScript code just before the closing <body> tag.
I also noticed you were triggering the validate function on button click. It is a problem if you are submitting the form via any other method than that (e.g. pressing enter on a focused input field). I added an event listener to the form itself, this should handle all common submit cases.
I made the users array have just one level, which contains all of the users. Each user has a type, which is used to determine the type of the user (regular user, admin user, supplier, etc.)
I have commented each line of the code below.
This script should NOT be used in production of any kind. It is dangerous as all checks are done client-side and client-side only. ALWAYS use server-side checks, preferably in test scripts too!
Click the Run Snippet button below to test the script here.
You can find the usernames and passwords from the array in the very beginning of the JavaScript script.
// store the IDs of all logged in users in here
var loggedusers = [];
// server should handle everything below...
// users array, which contains all users in the system
// on the server-side this could be an array returned by a MySQL database table, for example
var users = [{
// ID of the user
id: 1,
// username of the user
username: 'user1',
// password of the user, note that this should obviously be hashed on the server-side
// for PHP back-end: preferably hashed with 'password_hash' and compared using 'password_verify' if using PHP version 5.5 or newer
password: 'a',
// type of the user, currently using 'user', 'admin' and 'supplier', but technically it could be _anything_
type: 'user'
}, {
id: 2,
username: 'admin1',
password: 'b',
type: 'admin'
}, {
id: 3,
username: 'supplier1',
password: 'c',
type: 'supplier'
}];
// ... up to this point, never store this data on the client-side (especially highly sensitive information like hashes, salts, or even worse like plain text passwords like above).
/**
* null|Object getUserByProperty ( mixed key, mixed value [ , boolean strict = false, boolean multiple = false, boolean case_insensitive = false ] )
*
* Gets a user by a property key, value and various settings.
*
* #param mixed key Property key to look for.
* #param mixed value Property value to look for.
* #param boolean strict (optional) Should the comparison be type strict?
* #param boolean multiple (optional) Should it return all results, rather than the first result?
* #param boolean case_insensitive (optional) Should it ignore character case?
*
* #return null|Object Returns the user object, or null, if not found.
*/
function getUserByProperty(key, value, strict, multiple, case_insensitive) {
// prepare a result array
var result = [];
// loop through all of our users
for (var index in users) {
// get the user we are iterating through now
var user = users[index];
// check if the user has the specified property
if (typeof user[key] != 'undefined') {
// get the property value
var compare = user[key];
// doing something case insensitive
if (case_insensitive) {
// if the property value is a string
if (typeof compare == 'string')
// we want to turn it to lower case
compare = compare.toLowerCase();
// if the specified value is a string
if (typeof value == 'string')
// we want to turn it to lower case
value = value.toLowerCase();
}
// if specified value is not defined, or values match
if (typeof value == 'undefined' || ((strict && compare === value) || (!strict && compare == value))) {
// if we want multiple results
if (multiple) {
// the result will be appended to the result array
result.push(user);
} else {
// otherwise we just return it
return user;
}
}
}
}
// return the results or null, if nothing was found (for single match search)
return multiple ? result : null;
}
/**
* null|Object getUserById ( number id )
*
* Gets a user with the specified ID.
*
* #param number id ID of user to get.
*
* #return null|Object Returns the user object, or null, if not found.
*/
function getUserById(id) {
return getUserByProperty('id', id);
}
/**
* null|Object getUserByUsername ( string username [ , boolean case_insensitive = false ] )
*
* Gets a user with the specified username.
*
* #param string username Username of user to get.
* #param boolean case_insensitive Should character case be ignored?
*
* #return null|Object Returns the user object, or null, if not found.
*/
function getUserByUsername(username, case_insensitive) {
return getUserByProperty('username', username, false, false, case_insensitive);
}
/**
* boolean|array getUsersByType ( string type [ , boolean case_insensitive = false ] )
*
* Gets all users with the specified type.
*
* #param string type Type of user to look for.
* #param boolean case_insensitive Should character case be ignored?
*
* #return array Returns the an array of user objects.
*/
function getUsersByType(type, case_insensitive) {
return getUserByProperty('type', type, false, true, case_insensitive);
}
/**
* boolean|Object login ( string username, string password )
*
* Provides the functionality to be able to log in on a user.
*
* #param string username Username of the user to log in on.
* #param string password Password of the user to log in on.
*
* #return boolean|Object Returns the user object, or false, if login was not successful.
*/
function login(username, password) {
// checks whether username and password have been filled in
if (typeof username == 'string' && typeof password == 'string' && username.length > 0 && password.length > 0) {
// prepare a variable to store the user object, if any is received
var loggeduser;
// server should handle everything below...
// iterate through all users in the 'users' array (or database table perhaps, on server-side)
for (var index in users) {
// grab the property value with the property
var user = users[index];
// check if username and password match
if (username === user.username && password === user.password)
// set value of 'loggeduser' to the property value (user)
loggeduser = user;
}
// ... up to this point, and the user returned from the server should be set in to 'loggeduser'
// make sure highly sensitive information is not returned, such as hash, salt or anything
// check whether the user is set
if (typeof loggeduser != 'undefined') {
// save the ID of the user to the 'loggedusers' array
loggedusers[loggeduser.id] = true;
// update the logged in list
updatelist();
// return the received user object
return loggeduser;
}
}
return false;
}
/**
* boolean logout ( number userid )
*
* Provides the functionality to be able to log out from a user.
*
* #param number userid ID of the user to log out of.
*
* #return boolean Returns a boolean representing whether the log out was successful or not.
*/
function logout(userid) {
// check whether the ID is actually logged in
if (loggedusers[userid]) {
// temporary array, which we will be filling
var temporary = [];
// let's loop through logged users
for (var id in loggedusers)
// ignore our user
if (id != userid)
// let's put this user to the array
temporary[id] = true;
// we replace the 'loggedusers' array with our new array
loggedusers = temporary;
// update the logged in list
updatelist();
// we have successfully logged out
return true;
}
// we have not successfully logged out
return false;
}
/**
* boolean updatelist ( void )
*
* Provides the functionality to update the #logged-in-list element
* with the logged in users names and logout links.
*
* #return boolean Returns a boolean representing whether the update was successful or not.
*/
function updatelist() {
// get the #logged-in-list element
var list_element = document.getElementById('logged-in-list');
// check the element exists
if (list_element) {
// get the #logged-in element
var list_container_element = document.getElementById('logged-in');
// check the element exists and that we should be changing the styles
if (list_container_element)
// if there are no logged in users, "hide" the element, otherwise "show" it
list_container_element.style.visibility = loggedusers.length === 0 ? 'hidden' : 'visible';
// we take the first child with a while loop
while (list_element.firstChild)
// remove the child, and it will repeat doing so until there is no firstChild left for the list_element
list_element.removeChild(list_element.firstChild);
// we loop through every logged in user
for (var id in loggedusers) {
// get the user by ID
var user = getUserById(id);
// check if that user is a user
if (user) {
// we create necessary elements to cover our logout functionality
var p = document.createElement('P');
p.innerText = user.username;
var a = document.createElement('A');
a.userid = id;
a.href = '#';
a.innerHTML = '(logout)';
// we bind an onclick event listener to the link
a.addEventListener('click', function(e) {
e.preventDefault();
// we will now execute the logout function for this user ID
logout(e.srcElement.userid);
});
// we append the link to the paragraph element
p.appendChild(a);
// we append the paragraph to the list element
list_element.appendChild(p);
}
}
return true;
}
return false;
}
// add a new 'onsubmit' event listener to the '#login-form' node
// this will be triggered each time the form is submitted via any method
document.getElementById('login-form').addEventListener('submit', function(e) {
// prevent default browser behavior
e.preventDefault();
// find the username and password nodes
var username_element = e.srcElement.elements.username;
var password_element = e.srcElement.elements.password;
// check whether these elements return right stuff
if (username_element && password_element) {
// get the values of username and password
username = username_element.value;
password = password_element.value;
// execute the 'login' function with the username and password filled in on the client
var user = login(username, password);
// check whether the login was successful
if (user !== false) {
// reset the username input field
username_element.value = '';
// reset the password input field
password_element.value = '';
// alert the client that login was successful
alert('Logged in as ' + user.username + '.');
} else {
// reset the password input field
password_element.value = '';
// alert the client that login was not successful
alert('Invalid username and/or password.');
}
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login Form</title>
</head>
<body>
<div style="visibility: hidden;" id="logged-in">
<p><strong>Logged in as:</strong>
</p>
<div id="logged-in-list"></div>
</div>
<form id="login-form">
<h2>Login Form</h2>
<label for="username">Username:</label>
<input type="text" placeholder="Enter username..." id="username" />
<label for="password">Password:</label>
<input type="password" placeholder="Enter password..." id="password" />
<input type="submit" value="Login" />
</form>
<!-- the JavaScript code should go as contents of this tag -->
<script></script>
</body>
</html>
Please, to anyone using this code, do not use this, under any circumstance, in production. Always perform validations and comparisons server-side, along with client-side checks before the server-side checks to cut out any unnecessary processing on the server.
Hope this helps you!
<?php
function jumlah_like($url){
// Query di FQL
$myfql = "SELECT like_count, share_count, comment_count ";
$myfql .= " FROM link_stat WHERE url = '$url'";
$fqlURL = "https://api.facebook.com/method/fql.query?format=json&query=" . urlencode($myfql);
// Facebook Response dalam JSON
$response = file_get_contents($fqlURL);
return json_decode($response);
}
$page_name = "https://www.facebook.com/dumetschool/?ref=ts&fref=ts";
$fb = jumlah_like(https://www.facebook.com/gegegenogege);
//var_dump($fb);
// jumlah like facebook
echo "URL = ".$page_name;
echo "
<h1><small>Jumlah Like:</small> ". $fb[0]->like_count ."</h1>
";
?>
Related
I've already tried several tutorials, but I still couldn't create a user with a name to, for example, send the email in the tag %DISPLAY_NAME%
Here is the code I use to register users if it helps to solve the problem, if you have more doubts please send them in the comments
function register () {
// Get all our input fields
email = document.getElementById('email').value
password = document.getElementById('password').value
auth = document.getElementById('auth').value
favourite_song = document.getElementById('favourite_song').value
milk_before_cereal = document.getElementById('milk_before_cereal').value
// Validate input fields
if (validate_email(email) == false || validate_password(password) == false) {
alert('Email or Password is Outta Line!!')
return
// Don't continue running the code
}
if (validate_field(auth) == false || validate_field(favourite_song) == false || validate_field(milk_before_cereal) == false) {
alert('One or More Extra Fields is Outta Line!!')
return
}
// Move on with Auth
auth.createUserWithEmailAndPassword(email,auth, password)
.then(function() {
// Declare user variable
var user = auth.currentUser
// Add this user to Firebase Database
var database_ref = database.ref()
// Create User data
var user_data = {
email : email,
full_name : full_name,
favourite_song : favourite_song,
milk_before_cereal : milk_before_cereal,
last_login : Date.now()
}
// Push to Firebase Database
database_ref.child('users/' + user.uid).set(user_data)
// DOne
alert('User Created!!')
})
.catch(function(error) {
// Firebase will use this to alert of its errors
var error_code = error.code
var error_message = error.message
alert(error_message)
})
}
I have a function that takes data from an input and saves it as data in an array during registration. Now I want another function to check during login if the data exists and if it matches. How can I do this using javascript only?
In short, I need a function that checks if the data entered by the user exists and if so, logs him in.
function saveData() {
let name, email, password;
name = document.getElementById("username").value;
email = document.getElementById("email").value;
password = document.getElementById("password").value;
let user_records = new Array();
user_records = JSON.parse(localStorage.getItem("users"))
? JSON.parse(localStorage.getItem("users"))
: [];
if (
user_records.some((v) => {
return v.email == email;
})
) {
alert("Email wykorzystany");
} else {
user_records.push({
name: name,
email: email,
password: password,
});
localStorage.setItem("users", JSON.stringify(user_records));
}
}
I know that this is not how registration should be done. I am just doing it to learn new things.
this is a basic login, when you verify that the emmail and password are right, you can do wathever you want
function checkData() {
const name = document.getElementById('username').value;
const password = document.getElementById('password').value;
let user_records = JSON.parse(localStorage.getItem('users')) || [];
if (
user_records.find((user) => {
return user.name == name && user.password == password;
})
) {
alert('Logged in');
// do your things here
} else {
alert('wrong email or password');
// do your things here
}
}
<input id="username" />
<input id="password" />
<input type="submit" value="submit" onClick="checkData()" />
Extra:
This is a thing that you can do only for learning purpose, wich is to add a key to the local storage, for example: localStorage.setItem('loggedIn', true) and set in every page a check for this value, if is true show the page, if is false redirect to login. In the real world we use JWT tokens that contains all the information about the user etc... You can search for JWT token authentication on google and learn that, wich is really usefull in the front-end world
function saveAndTestUser() {
// here use const as they are not updated
const name = document.getElementById("username").value;
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;
// Get all the records of the users
// prefer camelcase : not a rule though but it's better this way
const storedUsers = localStorage.getItem('users')
// if there are no stored users then assign empty array
// so that we don't get unexpected errors
const userRecords = storedUsers ? JSON.parse(storedUsers): []
// Checking if email already exists
if(userRecords.some(user => user.email === email)){
alert("user already exists")
return false; // stops the function execution
}
// If email doesn't exists then the code below will be executed
// Similar to if-else
// Add current record to existing records
const newRecords = [...storedUsers, {name, email, password}]
// Set the new record to storage
localStorage.setItem("users", JSON.stringify(newRecords));
}
I'm new to coding and recently I've created a Google script (based on two other scripts) which does the following:
Searches for a Gmail draft by its subject line
Gets the Gmail draft and uses it as a template to create multiple drafts with unique attachments
Puts a confirmation phrase after drafts are created.
Here is the code:
//Change these to match the column names you are using for email recepient addresses and merge status column//
var RECIPIENT_COL = "Email";
var MERGE_STATUS_COL = "M";
//Creates the menu item "Mail Merge" for user to run scripts on drop-down//
function onOpen(e) {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Mail Merge')
.addItem('📌 Create Drafts', 'createDrafts').addToUi();
}
function createDrafts() {
// search for the draft Gmail message to merge with by its subject line
var subjectLine = Browser.inputBox("Select draft " + "to merge with:", "Paste the subject line:", Browser.Buttons.OK_CANCEL);
if (subjectLine === "cancel" || subjectLine == ""){
// if no subject line finish up
return;
}
// get the draft Gmail message to use as a template
var emailTemplate = getGmailTemplateFromDrafts_(subjectLine);
emailTemplate.subject = subjectLine;
// get the data from the active sheet
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getDataRange();
// fetch values for each row in the Range.
var data = dataRange.getValues();
// assuming row 1 contains our column headings
var header = data.shift();
// get the index of column named 'M' (Assume header names are unique)
var draftCreatedColIdx = header.indexOf(MERGE_STATUS_COL);
var object = data.map(function(row) {
// create a new object for next row using the header as a key
var nextRowObject = header.reduce(function(accumulator, currentValue, currentIndex) {
accumulator[currentValue] = row[currentIndex];
return accumulator;
}, {}) // Use {} here rather than initialAccumulatorValue
return nextRowObject;
});
// loop through all the rows of data
object.forEach(function(row, rowIdx){
// only create drafts if mail merge status cell is blank
if (row[MERGE_STATUS_COL] === ''){
var msgObj = fillInTemplateFromObject_(emailTemplate, row);
var attachment_id = "File Name";
// split the values taken from cell into array
var pdfName = row[attachment_id].split(', ');
// initialize files as empty array
var files = [];
// run through cell values and perform search
for(var j in pdfName){
// perform the search,results is a FileIterator
var results = DriveApp.getFilesByName(pdfName[j]);
// interate through files found and add to attachment results
while(results.hasNext()) {
// add files to array
files.push(results.next());
}
}
// #see https://developers.google.com/apps-script/reference/gmail/gmail-app#sendemailrecipient-subject-body-options
GmailApp.createDraft(row[RECIPIENT_COL], msgObj.subject, msgObj.text, {htmlBody: msgObj.html, attachments: files});
// create a confirmation phrase in the first column
sheet.getRange("A" + (rowIdx + 2)).setValue("DRAFT");
}
});
}
/**
* Get a Gmail draft message by matching the subject line.
* #param {string} subject_line to search for draft message
* #return {object} containing the plain and html message body
*/
function getGmailTemplateFromDrafts_(subject_line) {
try {
// get drafts
var drafts = GmailApp.getDrafts();
// filter the drafts that match subject line
var draft = drafts.filter(subjectFilter_(subject_line))[0];
// get the message object
var msg = draft.getMessage();
return {text: msg.getPlainBody(), html:msg.getBody()};
} catch(e) {
throw new Error("Oops - can't find Gmail draft");
}
}
/**
* Filter draft objects with the matching subject linemessage by matching the subject line.
* #param {string} subject_line to search for draft message
* #return {object} GmailDraft object
*/
function subjectFilter_(subject_line){
return function(element) {
if (element.getMessage().getSubject() === subject_line) {
return element;
}
}
}
/**
* Fill HTML string with data object.
* #param {string} template string containing {{}} markers which are replaced with data
* #param {object} data object used to replace {{}} markers
* #return {object} message replaced with data
* H/T https://developers.google.com/apps-script/articles/mail_merge
*/
function fillInTemplateFromObject_(template, data) {
// convert object to string for simple find and replace
template = JSON.stringify(template);
// Search for all the variables to be replaced, for instance {{Column name}}
var templateVars = template.match(/{{([^}]+)}}/g);
// Replace variables from the template with the actual values from the data object.
// If no value is available, replace with the empty string.
for (var i = 0; i < templateVars.length; ++i) {
// strip out {{ }}
var variableData = data[templateVars[i].substring(2, templateVars[i].length - 2)];
template = template.replace(templateVars[i], variableData || "");
}
// convert back to object
return JSON.parse(template);
}
The script works as expected but when I'm trying to process too many rows with too many attachments it exceeds a 6-minute Google Script maximum execution time.
While trying to solve this problem I found a simple script that uses a continuationToken and by doing so never exceeds the limit. My goal is to try to use the same principle in my own script and to process rows by tens. Unfortunatelly, I haven't had any luck so far and need some help. Here's the code of the script that I found:
Code.gs
function onOpen() {
SpreadsheetApp.getUi().createMenu("List Drive files").addItem('Start', 'start').addToUi();
}
function start() {
var ui = HtmlService.createHtmlOutputFromFile('ui');
return SpreadsheetApp.getUi().showSidebar(ui);
}
function getDriveFiles(continuationToken) {
if(continuationToken) {
var files = DriveApp.continueFileIterator(continuationToken);
}
else {
var files = DriveApp.getFiles();
}
var i = 0;
while (files.hasNext() && i < 10) {
var file = files.next();
SpreadsheetApp.getActiveSheet().appendRow([file.getName(), file.getUrl()]);
i++;
if(i == 10) {
return files.getContinuationToken();
}
}
}
ui.html
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<div style="text-align:center; margin-top:10px">
<div>Files processed:</div>
<div id="nbOfFilesProcessed">0</div>
<br>
<button id="startButton" class="blue" onclick="start()">Start</button>
<div class="secondary">Close the sidebar to stop the script.</div>
</div>
<script>
function start() {
document.getElementById("startButton").disabled = true;
google.script.run.withSuccessHandler(onSuccess).getDriveFiles();
}
function onSuccess(continuationToken){
// If server function returned a continuationToken it means the task is not complete
// so ask the server to process a new batch.
if(continuationToken) {
var nbOfFilesProcessedEl = document.getElementById("nbOfFilesProcessed");
nbOfFilesProcessedEl.innerHTML = parseInt(nbOfFilesProcessedEl.innerHTML) + 10;
google.script.run.withSuccessHandler(onSuccess).getDriveFiles(continuationToken);
}
}
</script>
From what I see in the code you posted you will have to edit your createDrafts function in this way:
Edit how the function is triggered: you will have to use an HTML ui element to run javascript inside it.
Edit the while loop so that it has a return statement when you hit the limit of your batch.
Create a Javascript function in the HTML ui element that handles the success of the createDrafts function and recursively calls it in case that the continuationToken is returned.
Snippets
UI Component
You can keep your custom menu and on click add this HTML to a UI dialog.
- code.gs -
//Creates the menu item "Mail Merge" for user to run scripts on drop-down//
function onOpen(e) {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Mail Merge')
.addItem('📌 Create Drafts', 'openDialog').addToUi();
}
function openDialog() {
// Display a modal dialog box with custom HtmlService content.
var htmlOutput = HtmlService
.createHtmlOutputFromFile('Dialog')
.setWidth(250)
.setHeight(300);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Create Drafts');
}
- Dialog.html -
<!-- The UI will be very similar to the one you found, I will keep only the strictly necessary statements for this example -->
<div>
<button id="startButton" onclick="startBatch()">Start</button>
</div>
<script>
function startBatch() {
google.script.run.withSuccessHandler(onSuccess).createDrafts();
}
function onSuccess(continuationToken){
// If server function returned a continuationToken it means the task is not complete
// so ask the server to process a new batch.
if(continuationToken) {
google.script.run.withSuccessHandler(onSuccess).createDrafts(continuationToken);
}
}
</script>
Apps Script Component
function createDrafts(continuationToken) {
var batchLimit = 10;
// ...
// run through cell values and perform search
for(var j in pdfName){
// perform the search,results is a FileIterator
if (continuationToken) {
var results = DriveApp.continueFileIterator(continuationToken);
} else {
var results = DriveApp.getFilesByName(pdfName[j]);
}
// interate through files found and add to attachment results
let i = 0;
while(results.hasNext() && i<batchLimit) {
// add files to array
files.push(results.next());
i++;
if (i === batchLimit) {
return results.getContinuationToken();
}
}
}
Final considerations
As an improvement to your batch operation, I would save all the user inputs so that you will be able to continue the script without prompting for it again. You can either pass these values to the return function on a javascript object or save them in the cache with the CacheService utility.
Moreover, try to find the correct trade off between execution time and batch limit: A small batch limit will never hit the time limit but will consume your quota very fast.
References:
Client Side API
Cache Service
Apps Script UI
So, I have a page object file that provides a number of methods for the elements on a page. The page is a login page with some text, a username and password input elements, and a login button. I've created a generic object called "InputLabel.js" which ties the label and input element together for testing purposes.
The problem I'm having is that after I clear the input, send the data, and then verify the data, I'm getting a Failed: Cannot read property 'verifyValue' of undefined error.
Here is the relevant code:
// InputLabel.js
function InputLabel(container) {
this.Container = container;
}
InputLabel.prototype = {
constructor: InputLabel,
// ...
/**
* Return the element for the input of the input/label combination of elements.
*
* #returns {ElementFinder}
*/
getInput: function () {
return this.Container.$('input');
},
/**
* Return the text shown in the input of the input/label combination of elements.
*
* #returns {Promise}
*/
getValue: function () {
return this.getInput().getAttribute('value');
},
/**
* Verify the text shown in the input of the input/label combination of elements.
*
* #param expected The expected text in the input element.
*/
verifyValue: function (expected) {
console.log('Asserting input value [' + expected + ']');
expect(this.getValue()).toEqual(expected);
},
// ...
/**
* Clears the input element then puts the text from data into the input element.
*
* #param data The text to be entered into the input element.
*/
sendKeys: function (data) {
var el = this.getInput();
el.clear().then(function () {
el.sendKeys(data).then(function () {
console.log("Verifying [" + data + "] was sent to the input.")
this.verifyValue(data);
});
});
}
};
After requiring the file, I can call any of these methods without issue except the sendKeys. If I disabled the this.verifyValue(data); method, sendKeys works fine.
// LoginPage.js
var InputLabel = require('InputLabel.js');
function LoginPage() {
}
var username = new InputLabel($('#username'));
var password = new InputLabel($('#password'));
function.prototype = {
// ...
username: username,
password: password,
loginButton: {
get: function() { return $('#Login'); },
click: function() { return this.get().click(); }
},
// ...
login: function(user, pw) {
this.username.sendKeys(user);
this.password.sendKeys(pw);
this.loginButton.click()
}
}
Am I losing something in scope? Again, the error is that it fails because it cannot read property 'verifyValue' of undefined after sending the keys.
You have a scoping issue with "this" keyword on the line containing "this.verifyValue(data);". In this case "this" keyword doesn't refer to the InputLabel class. Also it is considered a good practice to keep page objects assertion-free. See http://martinfowler.com/bliki/PageObject.html
As my app is growing, I'm finding more need for more effective form validation. I personally don't like the angular built in validation that evaluates on field change. And there are always things it won't account for like verifying that a youtube video id is valid. Currently I'm doing validation in each forms controller. I have a function that looks like this. Each field has a message and if there is an error the message will appear red using ng-class.
$scope.validate = function (callback) {
// reset default messages
setMessages();
// create shorter references
var item = $scope.item,
message = $scope.itemMessage;
// title exists
if (item.title === '') {
message.title.message = 'You must give your item a title.';
message.title.error = true;
message.errors += 1;
}
// extract and clear video id with youtube api
if ($scope.temp.video !== undefined && $scope.temp.video !== '') {
var id = '';
var url = $scope.temp.video.replace(/(>|<)/gi,'').split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/);
if(url[2] !== undefined) {
id = url[2].split(/[^0-9a-z_]/i);
id = id[0];
} else {
id = url;
}
$http.get("http://gdata.youtube.com/feeds/api/videos/" + id)
.then(function (res) {
$scope.item.video = id;
}, function (res) {
message.video.message = 'That is not a valid youtube video.';
message.video.error = true;
message.errors += 1;
$scope.item.video = '';
});
}
if (message.errors === 0) {
callback();
}
};
and then my actual form submission function calls $scope.validate(); passing it a function containing the $http.post(). The two major problems I see are that my callback isn't promise base so there's no guarantee it won't be called when an error exists and I've read again and again to keep large chunks of logic outside of your controller. I haven't found great examples of how this should be done but it must be a common problem.
You can still use Angular's built-in validation and have it not evaluate unless the form has been submitted:
http://scotch.io/tutorials/javascript/angularjs-form-validation#only-showing-errors-after-submitting-the-form
Essentially you set $scope.submitted = true when the form is submitted and set a conditional check so that error messages and classes are only shown when $scope.submitted is set.