Passing array of dates to Javascript sort - javascript

I'm having problem with javascript sort function. I have this function:
var compare = function(a, b) {
if(a.last_nom < b.last_nom) {
return -1;
}
if(a.last_nom > b.last_nom) {
return 1;
}
return 0;
}
And the I call it with:
var sortedData = fullData.sort(compare);
But I don't know how to pass dates correctly.
You can find jsbin example here
Thank you in advance
As requested, to make sense of my code here is full code:
<html lang="en-US">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/css/materialize.min.css">
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.0/sweetalert.min.css" rel="stylesheet">
<link rel="icon" href="http://www.mzirafos.lt/favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="http://www.mzirafos.lt/favicon.ico" type="image/x-icon" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mėmelio Žirafos - Facebook feeds page</title>
<style>
html {
overflow-y: scroll;
}
header {
margin-bottom: 50px;
}
.progress {
top: 50%;
width: 50%;
margin: 0 auto;
}
.event-only .not-event {
display: none;
}
.post-by {
display: block;
margin-bottom: 25px;
}
.post-date {
display: block;
}
.card .card-content .card-title {
line-height: 26px;
margin-bottom: 15px;
display: inline-block;
}
img.responsive-img {
width: 100%;
}
</style>
</head>
<body>
<div class="progress">
<div class="indeterminate"></div>
</div>
<div class="hide" id="content">
<!--header-->
<header>
<nav class="top-nav">
<div class="container">
<div class="nav-wrapper">
<p>Mėmelio Žirafos Facebook feeds page</p>
</div>
</div>
</nav>
</header>
<!--end header-->
<div class="container">
<div class="row">
<!--checkbox to show all posts or events only-->
<div class="col s6">
<p>
<input type="checkbox" id="events-only" />
<label for="events-only">Show events only</label>
</p>
</div>
<!--end checkbox-->
</div>
<div class="row">
<h3 class="center-align" id="posts-acc-title">Facebook posts</h3>
<!--posts wrapper-->
<div class="col s12" id="fb-posts-wrap"></div>
<!--end posts wrapper-->
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/js/materialize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sugar/1.4.1/sugar.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.0/sweetalert.min.js"></script>
<script src="https://cdn.rawgit.com/zenorocha/clipboard.js/master/dist/clipboard.min.js"></script>
<script>
(function() {
/*
* Our Globals
*/
var html = '';
var finalData = [];
var token = 'CAAQYWWjo5zkBAGlqs2AxxsWKcgWEI0VM3UA7555dhCQEOCTu9VW91tpfaNvrt4tS0w8DkxPJHvRENRrMeDT9QC1aSvHdZA7nhw9ZBqZAyUhMM6PTQoJggn7pJRHEO8xQJp8lsGZAqixVU8SvrMlhUUhwmzB11h9ISqd3MvmoD4aVZBPPD1geO';
var baseURL =
'https://graph.facebook.com/v2.4/{slug}/feed?fields=picture,created_time,message,link,type,description,caption,full_picture,id,admin_creator,from&limit=50&access_token={token}';
var slugs = [{
slug: 'sisaidgallery',
complete: false
}, {
slug: 'duzenos',
complete: false
}, {
slug: 'bbcnews',
complete: false
}, {
slug: 'Klaipeda.renginiai',
complete: false
}, {
slug: 'PORTbyBarBara',
complete: false
}, {
slug: 'Kastonas',
complete: false
}, {
slug: 'klaipedosdramosteatras',
complete: false
}, {
slug: '238899589464193',
complete: false
}];
/*
* allComplete
*/
var allComplete = function() {
for (var i = 0; i < slugs.length; i++) {
if (slugs[i].complete === false) {
return false;
}
}
return true;
};
/*
* makeURL
*/
var makeURL = function(url, token, slug) {
return url.replace('{token}', token).replace('{slug}', slug);
};
/*
* Date formatter
*/
var dateFormatter = function(date) {
var dateFormat = '{HH}:{mm}, {Weekday}, {d} {Month}, {yyyy}';
return Date.create(date).format(dateFormat);
}
/*
* Mark slug as complete
*/
var completeSlug = function(mySlug) {
for (var i in slugs) {
if (slugs[i].slug === mySlug) {
slugs[i].complete = true;
}
}
};
var copyTextID = 100;
/*
* template
*/
var template = '' +
'<div class="card blue-grey darken-1 hoverable {isEvent}">' +
'<div class="card-content white-text">' +
'<span class="post-date">Posted on: {fb-post-date}</span>' +
'<span class="post-by">Post by: {fb-post-from}</span>' +
'<div class="row">' +
'<div class="col s2">' +
'<img class="responsive-img" src="{fb-image}" alt=""/>' +
'</div>' +
'<div class="col s10" id="post-target-{fb-post-id}">' +
'<span class="card-title">{fb-post-title}</span>' +
'<p>{fb-post-text}</p>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="card-action">' +
'<a target="_blank" href="{fb-post-link}">Open post</a>' +
'<a class="waves-effect waves-light btn white-text red darken-1 hoverable" data-clipboard-target="#post-target-{fb-post-id}"><i class="material-icons right">subject</i>Copy</a>' +
'</div>' +
'</div>';
/*
* checking title, text and images
*/
var replaceUndefined = function(str) {
return str === undefined ? '' : str;
};
var replaceImage = function(str) {
return str === undefined ? 'https://placehold.it/350x150' : str;
};
/*
* bindTemplate
*/
var bindTemplate = function(template, obj) {
return template
.replace('{isEvent}', obj.type === 'event' ? '' : 'not-event')
.replace('{fb-image}', replaceImage(obj.picture))
.replace('{fb-post-from}', obj.from.name)
.replace('{fb-post-title}', replaceUndefined(obj.description))
.replace('{fb-post-text}', replaceUndefined(obj.message))
.replace('{fb-post-link}', obj.link)
.replace('{fb-post-date}', dateFormatter(obj.created_time))
.replace(/{fb-post-id}/g, obj.id);
};
var makeAjax = function(fbUrl, next, slug) {
$.ajax({
url: fbUrl
}).done(function(data) {
next(data, slug);
});
};
/*
* renderTemplate
*/
var renderTemplate = function() {
$('#fb-posts-wrap').html(html);
};
/*
* makeAjaxCalls
*/
var makeAjaxCalls = function(slugs) {
slugs.forEach(function(slug) {
makeAjax(makeURL(baseURL, token, slug.slug), showAllPosts, slug.slug);
});
};
/*
* Flatten data
*/
var flattenData = function(data) {
var fullData = [];
var empty = [];
data.forEach(function(row) {
fullData.push(row.data);
});
return empty.concat.apply(empty, fullData);
};
var compare = function(a, b) {
if (a.last_nom < b.last_nom) {
return -1;
}
if (a.last_nom > b.last_nom) {
return 1;
}
return 0;
}
var showAllPosts = function(data, slug) {
// Let's first mark this slug as complete
completeSlug(slug);
// And store our data
finalData.push(data);
if (allComplete()) {
// merge all data
var fullData = flattenData(finalData);
// sort all data and
var sortedData = fullData.sort(compare);
// build the html
sortedData.forEach(function(obj) {
html += bindTemplate(template, obj);
});
// call the renderTemplateFunction
renderTemplate();
// finally hide the progress bar
$('.progress').fadeOut();
$('#content').removeClass('hide');
}
};
/*
* Listen to the change in the checkbox
*/
$('#events-only').change(function() {
if ($(this).is(':checked')) {
// hide the non events with css
$('#fb-posts-wrap').addClass('event-only');
} else {
// show the non events with css
$('#fb-posts-wrap').removeClass('event-only');
}
});
/*
* Kick off
*/
makeAjaxCalls(slugs);
})();
</script>
</body>
</html>

What is last_nom? There is no such function in JS Date specification
Try this:
function compare(a, b) {
if (a.getTime() > b.getTime())
return 1;
if (a.getTime() < b.getTime())
return -1;
return 0
}
var sortedDatesArray = unsortedDatesArray.sort(compare);

Related

Create a file with the same name as the folder where a file was uploaded

I have an HTML form within a Web App, created with GAS.
This HTML form was created from this file upload script here:
drive-multi-upload
This is the HTML form:
The point is that I needed the files to be uploaded in folders that follow the following pattern:
The first number refers to the model selected on the form, the second number refers to the slot used.
Therefore, it was necessary to create a function to identify the input chosen in the Model and, according to this input, check which is the first empty folder, then take the ID of that folder and pass it to the client side to upload the file inside it.
With the help of some members of the community, some adaptations were made and the final function was this:
/** Modified version of script written by Tanaike */
function createOrGetFolder(folderName, parentFolderId) {
try {
var parentFolder = DriveApp.getFolderById(parentFolderId), folder;
if (parentFolder) {
var foldersIter = parentFolder.getFoldersByName("Video");
if (foldersIter.hasNext()) {
var videoFolder = foldersIter.next();
var nextFolderName = folderName + "-01";
while (!folder) {
video_folder = videoFolder.getFoldersByName(nextFolderName);
if (video_folder.hasNext()) {
folder = video_folder.next();
var files = folder.getFiles();
if (files.hasNext()) {
var [a, b] = nextFolderName.split("-");
nextFolderName = `${a}-${String(Number(b) + 1).padStart(2, "0")}`;
folder = null;
}
} else {
folder = videoFolder.createFolder(nextFolderName);
}
}
} else {
folder = parentFolder.createFolder("Video");
folder = folder.createFolder(folderName);
}
} else {
throw new Error("Parent Folder with id: " + parentFolderId + " not found");
}
return folder.getId();
} catch (error) {
return error;
}
}
It works perfectly, the point is that this form also has a function that generates a .csv file when the form is submitted, the function is this one:
.gs file:
const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile("Sample.csv", data);
HTML file:
var name = $('#name01').val();
var description = $('#description').val();
var model = $('#Model').val();
upload_folder = model;
var color = $('#Color').val();
var form_values = [name, description, model, color];
var data = form_values.join(",");
google.script.run.saveDataAsCSV(data, uploadParentFolderId);
My goal is to make the .csv file be generated with the same name as the folder where the file was uploaded, that is, if the file is uploaded in folder 01-01, the file name has to be 01-01.csv, if the file is uploaded in the 02-02 folder, the file name has to be 02-02.csv, and so on.
How can I achieve this?
The complete script code can be viewed here:
.gs file:
function doGet(e) {
return HtmlService.createTemplateFromFile('forms0101.html').evaluate();
}
function getOAuthToken() {
return ScriptApp.getOAuthToken();
}
function getParent(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var id = ss.getId();
var parent = DriveApp.getFileById(id).getParents().next().getId();
return parent
}
function getLimitFolder(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var pastapai = DriveApp.getFileById(ss.getId()).getParents();
var limitfolder = pastapai.next().getFoldersByName("_").next().getId();
return limitfolder;
}
function getFilesLimit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var pastapai = DriveApp.getFileById(ss.getId()).getParents();
var files = [];
Logger.log(pastapai);
//var limitfolder = pastapai.next().getFoldersByName("_").next().getId();
var limitfolder = pastapai.next().getFoldersByName("_").next().getFiles();
while(limitfolder.hasNext()){
var file = limitfolder.next();
files.push([file.getId()]);
}
console.log(files.length);
return files.length;
}
//function testenumeroarquivos(){
//console.log(checkForFiles()); // When you use this line, you can see the filename of the files.
//}
/**
* creates a folder under a parent folder, and returns it's id. If the folder already exists
* then it is not created and it simply returns the id of the existing one
*/
function createOrGetFolder(folderName, parentFolderId) {
try {
var parentFolder = DriveApp.getFolderById(parentFolderId), folder;
if (parentFolder) {
var foldersIter = parentFolder.getFoldersByName("Video");
if (foldersIter.hasNext()) {
var videoFolder = foldersIter.next();
var nextFolderName = folderName + "-01";
while (!folder) {
video_folder = videoFolder.getFoldersByName(nextFolderName);
if (video_folder.hasNext()) {
folder = video_folder.next();
var files = folder.getFiles();
if (files.hasNext()) {
var [a, b] = nextFolderName.split("-");
nextFolderName = `${a}-${String(Number(b) + 1).padStart(2, "0")}`;
folder = null;
}
} else {
folder = videoFolder.createFolder(nextFolderName);
}
}
} else {
folder = parentFolder.createFolder("Video");
folder = folder.createFolder(folderName);
}
} else {
throw new Error("Parent Folder with id: " + parentFolderId + " not found");
}
console.log("Test" + nextFolderName)
return folder.getId();
} catch (error) {
return error;
}
}
const saveDataAsCSV = (data, folderId) => {
const folder = DriveApp.getFolderById(folderId);
folder.createFile(`${nextFolderName.getName()}.csv`, data);
}
const increaseRequest = (data, folderId) => DriveApp.getFolderById(folderId).createFile("IncreaseRequest.csv", data);
// NOTE: always make sure we use DriveApp, even if it's in a comment, for google to import those
// libraries and allow the rest of the app to work. see https://github.com/tanaikech/Resumable_Upload_For_WebApps
HTML file:
<!DOCTYPE html>
<html>
<head>
<base target="_blank">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Drive Multi Large File Upload</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<style>
#import url('https://fonts.googleapis.com/css2?family=Rubik:wght#400;600;700&display=swap');
.disclaimer{
width: 480px;
color: #646464;
margin: 20px auto;
padding:0 16px;
text-align:center;
font:400 12px Rubik,sans-serif;
}
h5.center-align.teal-text {
font:700 26px Rubik,sans-serif;
color: #00F498!important;
}
.row {
font:600 14px Rubik,sans-serif;
}
.btn {
background-color: black;
}
.btn:hover {
background-color: #00F498;
}
body {
margin-top: -40px;
}
#progress {
color: #00000;
}
.disclaimer a{
color: #00BCAA;
}
#credit{
display:none
}
.btnOpenModal {
font-size: x-large;
padding: 10px;
border: none;
border-radius: 5px;
background-color: blueviolet;
color: white;
cursor: pointer;
}
hr {
border: 0px;
border-top: 1px solid lightgray;
}
.modal-container {
width: 100vw;
position: fixed;
top: 30px;
display: none;
z-index: 999;
justify-content: center;
}
.modal {
display: flex;
flex-direction: column;
padding: 30px;
background-color: white;
border-radius: 10px;
width: 50%;
}
.active {
display: flex;
}
.active .modal {
animation: modal .4s;
}
#keyframes modal {
from {
opacity: 0;
transform: translate3d(0, -60px, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.btns {
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.btns button {
font-size: medium;
padding: 10px;
border: none;
border-radius: 5px;
color: white;
cursor: pointer;
}
.btnOK {
background-color: blue!important;
}
.btnClose {
background-color: brown!important;
}
</style>
</head>
<body>
<form class="main" id="form" novalidate="novalidate" style="max-width: 480px;margin: 40px auto;">
<div id="forminner">
<div class="modal-container">
<div class="modal">
<h2>Info</h2>
<hr />
<span>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of
type and scrambled it to make a type specimen book.
</span>
<hr />
<div class="btns">
<button class="btnOK" onclick="increaseRequest(); closeModal();">OK</button>
<button class="btnClose" onclick="closeModal()">Close</button>
</div>
</div>
</div>
<h5 class="center-align teal-text" style="margin-bottom: -10px; font-size: 20px; font-family: Rubik; ">YOUR NAME</h5>
<div class="row">
<div class="input-field col s12">
<input id="name01" type="text" name="Name" class="validate" required="required" aria-required="true">
<label for="name" class="">Name</label>
</div>
</div>
<h5 class="center-align teal-text" style="margin-bottom: -10px; font-size: 20px; font-family: Rubik; ">SOME DESCRIPTION</h5>
<div class="row">
<div class="input-field col s12">
<input id="description" type="text" name="Description" class="validate" required="required" aria-required="true">
<label for="name">Description</label>
</div>
</div>
<div class="row">
<div class="col-8 col-md-4">
<h6>Model</h6>
<select class="custom-select" id="Model">
<option selected="">Choose...</option>
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
</select>
<h6>Color</h6>
<select class="custom-select" id="Color">
<option selected="">Choose...</option>
<option value="Red">Red</option>
<option value="Green">Green</option>
</select>
</div>
</div>
<div class="row">
<div class="col s12">
<h5 class="center-align teal-text">Upload the Video File</h5>
</div>
</div>
<div class="row">
<div class="file-field input-field col s12">
<div id="input-btn" class="btn">
<span>File</span>
<input id="files" type="file" single="">
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="Select the file">
</div>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<button id="submit-btn" class="waves-effect waves-light btn submit-btn" type="submit" onclick="submitForm(); return false;">Submit</button>
</div>
</div>
<div class="row">
<div class="input-field col s12 hide" id="update">
<hr>
<p>
Por favor, aguarde enquanto seu arquivo está sendo carregado.<br><span style="color: #00000;"><b>Não feche ou atualize a janela durante o upload.</b></span>
</p>
</div>
</div>
<div class="row">
<div class="input-field col s12" id="progress">
</div>
</div>
</div>
</div>
<div id="success" style="display:none">
<h5 class="center-align teal-text">Tudo certo!</h5>
<p>Se você já preencheu todos os campos é só fechar essa janela e clicar em enviar!</p>
<button id="fechar" class="waves-effect waves-light btn submit-btn" style ="transform: translateX(160%);" type="button" onclick="google.script.host.close()">Fechar</button>
</div>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script>
<script src="https://gumroad.com/js/gumroad.js"></script>
<script>
var upload_folder = "01";
const chunkSize = 5242880;
const uploadParentFolderId = <?=getParent()?>; // creates a folder inside of this folder
const limitfolder = <?=getLimitFolder()?>;
const fileslimit = <?=getFilesLimit()?>;
const modal = document.querySelector('.modal-container');
var name = $('#name01').val();
var description = $('#description').val();
var model = $('#Model').val();
upload_folder = model;
var color = $('#Color').val();
var form_values = [name, description, model, color];
form_values = form_values.map(r => r.replaceAll(",", "#")); // Essa linha substitui todas as "," por "#" antes de gerar o .csv
var data = form_values.join(",");
function submitForm() {
var name = $('#name01').val();
var description = $('#description').val();
var model = $('#Model').val();
upload_folder = model;
var color = $('#Color').val();
var form_values = [name, description, model, color];
form_values = form_values.map(r => r.replaceAll(",", "#")); // Essa linha substitui todas as "," por "#" antes de gerar o .csv
var data = form_values.join(",");
// Added the below script.
if ($('#submit-btn.disabled')[0]) return; // short circuit
var name = upload_folder
var files = [...$('#files')[0].files]; // convert from FileList to array
if (files.length === 0) {
showError("Por favor, selecione um arquivo");
return;
}
google.script.run.saveDataAsCSV(data, uploadParentFolderId);
google.script.run.saveDataAsCSV(data, limitfolder);
disableForm(); // prevent re submission
// the map and reduce are here to ensure that only one file is uploaded at a time. This allows
// the promises to be run sequentially
files.map(file => uploadFilePromiseFactory(file))
.reduce((promiseChain, currentTask) => {
return promiseChain.then(currentTask);
}, Promise.resolve([])).then( () => {
console.log("Completed all files upload");
showSuccess();
});
}
function checkforfiles() {
if (fileslimit <= 2) {
submitForm();
}
if (fileslimit == 3) {
openModal();
}
if (fileslimit >= 4) {
showError("erro");
return;
}
}
function openModal() {
modal.classList.add('active');
}
function closeModal() {
modal.classList.remove('active');
}
function increaseRequest() {
google.script.run.increaseRequest(data, limitfolder);
}
function disableForm() {
$('#submit-btn').addClass('disabled');
$('#input-btn').addClass('disabled');
$('#update').removeClass('hide');
$('#update').removeClass('hide');
}
function closer(){
google.script.host.close();
}
function uploadFilePromiseFactory(file) {
return () => {
console.log("Processing: ", file.name);
return new Promise((resolve, reject) => {
showProgressMessage("Seu arquivo está sendo carregado");
var fr = new FileReader();
fr.fileName = file.name;
fr.fileSize = file.size;
fr.fileType = file.type;
// not sure of a better way of passing the promise functions down
fr.resolve = () => resolve();
fr.reject = (error) => reject(error);
fr.onload = onFileReaderLoad;
fr.readAsArrayBuffer(file);
});
};
}
/**
* Gets called once the browser has loaded a file. The main logic that creates a folder
* and initiates the file upload resides here
*/
function onFileReaderLoad(onLoadEvent) {
var fr = this;
var newFolderName = upload_folder
createOrGetFolder(newFolderName, uploadParentFolderId).then(newFolderId => {
console.log("Found or created guest folder with id: ", newFolderId);
uploadFileToDriveFolder.call(fr, newFolderId).then(() => {
fr.resolve();
}, (error) => {
fr.reject(error);
});
},
(error) => {
if (error) {
showError(error.toString());
}
console.log("onFileReaderLoad Error2: ", error);
});
}
/**
* call to the DriveApp api. Wrapped in a promise in case I want to address timing issues between a
* createFolder and findFolderById
*/
function createOrGetFolder(folderName, parentFolderId) {
return new Promise((resolve, reject) => {
google.script.run.withSuccessHandler(response => {
console.log("createOrGetFolder response: ", response);
if (response && response.length) {
resolve(response);
}
reject(response);
}).createOrGetFolder(folderName, parentFolderId);
});
}
/**
* Helper functions modified from:
* https://github.com/tanaikech/Resumable_Upload_For_WebApps
*/
function uploadFileToDriveFolder(parentFolderId) {
var fr = this;
return new Promise((resolve, reject) => {
var fileName = fr.fileName;
var fileSize = fr.fileSize;
var fileType = fr.fileType;
console.log({fileName: fileName, fileSize: fileSize, fileType: fileType});
var buf = fr.result;
var chunkpot = getChunkpot(chunkSize, fileSize);
var uint8Array = new Uint8Array(buf);
var chunks = chunkpot.chunks.map(function(e) {
return {
data: uint8Array.slice(e.startByte, e.endByte + 1),
length: e.numByte,
range: "bytes " + e.startByte + "-" + e.endByte + "/" + chunkpot.total,
};
});
google.script.run.withSuccessHandler(oAuthToken => {
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");
xhr.setRequestHeader('Authorization', "Bearer " + oAuthToken);
xhr.setRequestHeader('Content-Type', "application/json");
xhr.send(JSON.stringify({
mimeType: fileType,
name: fileName,
parents: [parentFolderId]
}));
xhr.onload = () => {
doUpload(fileName, {
location: xhr.getResponseHeader("location"),
chunks: chunks,
}).then(success => {
resolve(success);
console.log("Successfully uploaded: ", fileName);
},
error => {
reject(error);
});
};
xhr.onerror = () => {
console.log("ERROR: ", xhr.response);
reject(xhr.response);
};
}).getOAuthToken();
});
}
function showSuccess() {
$('#forminner').hide();
$('#success').show();
$('#fechar').show();
}
function showError(e) {
$('#progress').addClass('red-text').html(e);
}
function showMessage(e) {
$('#update').html(e);
}
function showProgressMessage(e) {
$('#progress').removeClass('red-text').html(e);
}
/**
* Helper functions modified from:
* https://github.com/tanaikech/Resumable_Upload_For_WebApps
*/
function doUpload(fileName, e) {
return new Promise((resolve, reject) => {
showProgressMessage("Carregando: <span style='color: #00F498 ;'>" + "0%</span>");
var chunks = e.chunks;
var location = e.location;
var cnt = 0;
var end = chunks.length;
var temp = function callback(cnt) {
var e = chunks[cnt];
var xhr = new XMLHttpRequest();
xhr.open("PUT", location, true);
console.log("content range: ", e.range);
xhr.setRequestHeader('Content-Range', e.range);
xhr.send(e.data);
xhr.onloadend = function() {
var status = xhr.status;
cnt += 1;
console.log("Uploading: " + status + " (" + cnt + " / " + end + ")");
showProgressMessage("Carregando: <span style='color: #00F498 ;'>"
+ Math.floor(100 * cnt / end) + "%</span>" );
if (status == 308) {
callback(cnt);
} else if (status == 200) {
$("#progress").text("Done.");
resolve();
} else {
$("#progress").text("Error: " + xhr.response);
reject();
}
};
}(cnt);
});
}
/**
* Helper functions modified from:
* https://github.com/tanaikech/Resumable_Upload_For_WebApps
*/
function getChunkpot(chunkSize, fileSize) {
var chunkPot = {};
chunkPot.total = fileSize;
chunkPot.chunks = [];
if (fileSize > chunkSize) {
var numE = chunkSize;
var endS = function(f, n) {
var c = f % n;
if (c == 0) {
return 0;
} else {
return c;
}
}(fileSize, numE);
var repeat = Math.floor(fileSize / numE);
for (var i = 0; i <= repeat; i++) {
var startAddress = i * numE;
var c = {};
c.startByte = startAddress;
if (i < repeat) {
c.endByte = startAddress + numE - 1;
c.numByte = numE;
chunkPot.chunks.push(c);
} else if (i == repeat && endS > 0) {
c.endByte = startAddress + endS - 1;
c.numByte = endS;
chunkPot.chunks.push(c);
}
}
} else {
var chunk = {
startByte: 0,
endByte: fileSize - 1,
numByte: fileSize,
};
chunkPot.chunks.push(chunk);
}
return chunkPot;
}
</script>
</body>
</html>
It can also be viewed by accessing this worksheet
Although I'm not sure whether I could correctly understand your actual expected result, please test the following modification.
Google Apps Script side:
Please modify saveDataAsCSV of Google Apps Script as follows.
const saveDataAsCSV = (data, folderId1, folderId2 = null) => {
if (folderId2) {
DriveApp.getFolderById(folderId1).createFile(`${DriveApp.getFolderById(folderId2).getName()}.csv`, data);
} else {
DriveApp.getFolderById(folderId1).createFile("sample.csv", data);
}
}
Javascript side:
Please remove google.script.run.saveDataAsCSV(data, uploadParentFolderId); in the function submitForm.
And, please modify onFileReaderLoad of Javascript as follows.
function onFileReaderLoad(onLoadEvent) {
var fr = this;
var newFolderName = upload_folder
createOrGetFolder(newFolderName, uploadParentFolderId).then(newFolderId => {
google.script.run.saveDataAsCSV(data, uploadParentFolderId, newFolderId);
console.log("Found or created guest folder with id: ", newFolderId);
uploadFileToDriveFolder.call(fr, newFolderId).then(() => {
fr.resolve();
}, (error) => {
fr.reject(error);
});
},
(error) => {
if (error) {
showError(error.toString());
}
console.log("onFileReaderLoad Error2: ", error);
});
}
By this modification, I think that a CSV file like 01-01.csv is created to uploadParentFolderId folder.

Instantiate ES6 class

I am trying to implement the following tags with my design.
I am using the class Tags to simply create tags within my input field, however when I initialize the library I get an error.
const ACTIVE_CLASS = "bg-light";
const VALUE_ATTRIBUTE = "data-value";
class Tags {
/**
* #param {HTMLSelectElement} selectElement
*/
constructor(selectElement) {
this.selectElement = selectElement;
this.selectElement.style.display = "none";
this.placeholder = this.getPlaceholder();
this.allowNew = selectElement.dataset.allowNew ? true : false;
// Create elements
this.holderElement = document.createElement("div");
this.containerElement = document.createElement("div");
this.dropElement = document.createElement("ul");
this.searchInput = document.createElement("input");
this.holderElement.appendChild(this.containerElement);
this.containerElement.appendChild(this.searchInput);
this.holderElement.appendChild(this.dropElement);
// insert after
this.selectElement.parentNode.insertBefore(this.holderElement, this.selectElement.nextSibling);
// Configure them
this.configureSearchInput();
this.configureHolderElement();
this.configureDropElement();
this.configureContainerElement();
this.buildSuggestions();
}
/**
* Attach to all elements matched by the selector
* #param {string} selector
*/
static init(selector = "select[multiple]") {
let list = document.querySelectorAll(selector);
for (let i = 0; i < list.length; i++) {
let el = list[i];
let inst = new Tags(el);
}
}
/**
* #returns {string}
*/
getPlaceholder() {
let firstOption = this.selectElement.querySelector("option");
if (!firstOption) {
return;
}
if (!firstOption.value) {
let placeholder = firstOption.innerText;
firstOption.remove();
return placeholder;
}
if (this.selectElement.getAttribute("placeholder")) {
return this.selectElement.getAttribute("placeholder");
}
if (this.selectElement.getAttribute("data-placeholder")) {
return this.selectElement.getAttribute("data-placeholder");
}
return "";
}
configureDropElement() {
this.dropElement.classList.add("dropdown-menu");
}
configureHolderElement() {
this.holderElement.classList.add("form-control");
this.holderElement.classList.add("dropdown");
}
configureContainerElement() {
this.containerElement.addEventListener("click", (event) => {
this.searchInput.focus();
});
// add initial values
let initialValues = this.selectElement.querySelectorAll("option[selected]");
for (let j = 0; j < initialValues.length; j++) {
let initialValue = initialValues[j];
if (!initialValue.value) {
continue;
}
this.addItem(initialValue.innerText, initialValue.value);
}
}
configureSearchInput() {
this.searchInput.type = "text";
this.searchInput.autocomplete = false;
this.searchInput.style.border = 0;
this.searchInput.style.outline = 0;
this.searchInput.style.maxWidth = "100%";
this.adjustWidth();
this.searchInput.addEventListener("input", (event) => {
this.adjustWidth();
if (this.searchInput.value.length >= 1) {
this.showSuggestions();
} else {
this.hideSuggestions();
}
});
// keypress doesn't send arrow keys
this.searchInput.addEventListener("keydown", (event) => {
if (event.code == "Enter") {
let selection = this.getActiveSelection();
if (selection) {
this.addItem(selection.innerText, selection.getAttribute(VALUE_ATTRIBUTE));
this.resetSearchInput();
this.hideSuggestions();
} else {
// We use what is typed
if (this.allowNew) {
this.addItem(this.searchInput.value);
this.resetSearchInput();
this.hideSuggestions();
}
}
event.preventDefault();
return;
}
if (event.code == "ArrowUp") {
this.moveSelectionUp();
}
if (event.code == "ArrowDown") {
this.moveSelectionDown();
}
if (event.code == "Backspace") {
if (this.searchInput.value.length == 0) {
this.removeLastItem();
this.adjustWidth();
}
}
});
}
moveSelectionUp() {
let active = this.getActiveSelection();
if (active) {
let prev = active.parentNode;
do {
prev = prev.previousSibling;
} while (prev && prev.style.display == "none");
if (!prev) {
return;
}
active.classList.remove(ACTIVE_CLASS);
prev.querySelector("a").classList.add(ACTIVE_CLASS);
}
}
moveSelectionDown() {
let active = this.getActiveSelection();
if (active) {
let next = active.parentNode;
do {
next = next.nextSibling;
} while (next && next.style.display == "none");
if (!next) {
return;
}
active.classList.remove(ACTIVE_CLASS);
next.querySelector("a").classList.add(ACTIVE_CLASS);
}
}
/**
* Adjust the field to fit its content
*/
adjustWidth() {
if (this.searchInput.value) {
this.searchInput.size = this.searchInput.value.length + 1;
} else {
// Show the placeholder only if empty
if (this.getSelectedValues().length) {
this.searchInput.placeholder = "";
this.searchInput.size = 1;
} else {
this.searchInput.size = this.placeholder.length;
this.searchInput.placeholder = this.placeholder;
}
}
}
/**
* Add suggestions from element
*/
buildSuggestions() {
let options = this.selectElement.querySelectorAll("option");
for (let i = 0; i < options.length; i++) {
let opt = options[i];
if (!opt.getAttribute("value")) {
continue;
}
let newChild = document.createElement("li");
let newChildLink = document.createElement("a");
newChild.append(newChildLink);
newChildLink.classList.add("dropdown-item");
newChildLink.setAttribute(VALUE_ATTRIBUTE, opt.getAttribute("value"));
newChildLink.setAttribute("href", "#");
newChildLink.innerText = opt.innerText;
this.dropElement.appendChild(newChild);
// Hover sets active item
newChildLink.addEventListener("mouseenter", (event) => {
this.removeActiveSelection();
newChild.querySelector("a").classList.add(ACTIVE_CLASS);
});
newChildLink.addEventListener("click", (event) => {
event.preventDefault();
this.addItem(newChildLink.innerText, newChildLink.getAttribute(VALUE_ATTRIBUTE));
this.resetSearchInput();
this.hideSuggestions();
});
}
}
resetSearchInput() {
this.searchInput.value = "";
this.adjustWidth();
}
/**
* #returns {array}
*/
getSelectedValues() {
let selected = this.selectElement.querySelectorAll("option:checked");
return Array.from(selected).map((el) => el.value);
}
/**
* The element create with buildSuggestions
*/
showSuggestions() {
if (!this.dropElement.classList.contains("show")) {
this.dropElement.classList.add("show");
}
// Position next to search input
this.dropElement.style.left = this.searchInput.offsetLeft + "px";
// Get search value
let search = this.searchInput.value.toLocaleLowerCase();
// Get current values
let values = this.getSelectedValues();
// Filter the list according to search string
let list = this.dropElement.querySelectorAll("li");
let found = false;
let firstItem = null;
for (let i = 0; i < list.length; i++) {
let item = list[i];
let text = item.innerText.toLocaleLowerCase();
let link = item.querySelector("a");
// Remove previous selection
link.classList.remove(ACTIVE_CLASS);
// Hide selected values
if (values.indexOf(link.getAttribute(VALUE_ATTRIBUTE)) != -1) {
item.style.display = "none";
continue;
}
if (text.indexOf(search) !== -1) {
item.style.display = "list-item";
found = true;
if (!firstItem) {
firstItem = item;
}
} else {
item.style.display = "none";
}
}
// Special case if nothing matches
if (!found) {
this.dropElement.classList.remove("show");
}
// Always select first item
if (firstItem) {
if (this.holderElement.classList.contains("is-invalid")) {
this.holderElement.classList.remove("is-invalid");
}
firstItem.querySelector("a").classList.add(ACTIVE_CLASS);
} else {
// No item and we don't allow new items => error
if (!this.allowNew) {
this.holderElement.classList.add("is-invalid");
}
}
}
/**
* The element create with buildSuggestions
*/
hideSuggestions(dropEl) {
if (this.dropElement.classList.contains("show")) {
this.dropElement.classList.remove("show");
}
if (this.holderElement.classList.contains("is-invalid")) {
this.holderElement.classList.remove("is-invalid");
}
}
/**
* #returns {HTMLElement}
*/
getActiveSelection() {
return this.dropElement.querySelector("a." + ACTIVE_CLASS);
}
removeActiveSelection() {
let selection = this.getActiveSelection();
if (selection) {
selection.classList.remove(ACTIVE_CLASS);
}
}
removeLastItem() {
let items = this.containerElement.querySelectorAll("span");
if (!items.length) {
return;
}
let lastItem = items[items.length - 1];
this.removeItem(lastItem.getAttribute(VALUE_ATTRIBUTE));
}
/**
* #param {string} text
* #param {string} value
*/
addItem(text, value) {
if (!value) {
value = text;
}
let span = document.createElement("span");
span.classList.add("badge");
span.classList.add("bg-primary");
span.classList.add("me-2");
span.setAttribute(VALUE_ATTRIBUTE, value);
span.innerText = text;
this.containerElement.insertBefore(span, this.searchInput);
// update select
let opt = this.selectElement.querySelector('option[value="' + value + '"]');
if (opt) {
opt.setAttribute("selected", "selected");
} else {
// we need to create a new option
opt = document.createElement("option");
opt.value = value;
opt.innerText = text;
opt.setAttribute("selected", "selected");
this.selectElement.appendChild(opt);
}
}
/**
* #param {string} value
*/
removeItem(value) {
let item = this.containerElement.querySelector("span[" + VALUE_ATTRIBUTE + '="' + value + '"]');
if (!item) {
return;
}
item.remove();
// update select
let opt = this.selectElement.querySelector('option[value="' + value + '"]');
if (opt) {
opt.removeAttribute("selected");
}
}
}
export default Tags;
import Tags
Tags.init();
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="generator" content="Hugo 0.80.0">
<title>Insider</title>
<link rel="canonical" href="">
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.4.0/font/bootstrap-icons.css">
<!-- Favicons -->
<link rel="apple-touch-icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/apple-touch-icon.png" sizes="180x180">
<link rel="icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/favicon-32x32.png" sizes="32x32" type="image/png">
<link rel="icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/favicon-16x16.png" sizes="16x16" type="image/png">
<link rel="manifest" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/manifest.json">
<link rel="mask-icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/safari-pinned-tab.svg" color="#7952b3">
<link rel="icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/favicon.ico">
<meta name="theme-color" content="#7952b3">
<!-- Custom styles for this template -->
<link href="https://unpkg.com/bootstrap-table#1.18.3/dist/bootstrap-table.min.css" rel="stylesheet">
</head>
<body>
<header class="p-3 bg-dark text-white">
<div class="container">
<div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
<ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
<li>
<button class="btn btn-outline-light" type="button" data-bs-toggle="modal" data-bs-target="#exampleModal">Check
</button>
</li>
</ul>
</div>
</div>
</header>
<main class="container pt-3">
<div class="row mt-3">
<h2>Content</h2>
</div>
</main>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Your Check</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<br>
<p class="h2">Check</p>
<p>Input your symbols and we will send you all relevant information.</p>
<br>
<form>
<div class="col">
<select class="form-select" id="validationTags" multiple="" data-allow-new="true" style="display: none;">
<option value="1" selected="selected">JavaScript</option>
<option value="2">HTML5</option>
<option value="3">CSS3</option>
<option value="4">jQuery</option>
<option value="5">React</option>
<option value="6">Angular</option>
<option value="7">Vue</option>
<option value="8">Python</option>
</select>
<div class="form-control dropdown">
<div><span class="badge bg-primary me-2" data-value="1">JavaScript</span><input type="text" autocomplete="false" placeholder="" size="1" style="border: 0px; outline: 0px; max-width: 100%;">
</div>
<ul class="dropdown-menu">
<li><a class="dropdown-item" data-value="1" href="#">JavaScript</a></li>
<li><a class="dropdown-item" data-value="2" href="#">HTML5</a></li>
<li><a class="dropdown-item" data-value="3" href="#">CSS3</a></li>
<li><a class="dropdown-item" data-value="4" href="#">jQuery</a></li>
<li><a class="dropdown-item" data-value="5" href="#">React</a></li>
<li><a class="dropdown-item" data-value="6" href="#">Angular</a></li>
<li><a class="dropdown-item" data-value="7" href="#">Vue</a></li>
<li><a class="dropdown-item" data-value="8" href="#">Python</a></li>
</ul>
</div>
<div class="invalid-feedback">Please select a valid tag.</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</div>
<!-- Modal END -->
<footer class="text-muted py-5">
<div class="container">
<p class="mb-1">Footer</p>
</div>
</footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/js/bootstrap.bundle.min.js" integrity="sha384-b5kHyXgcpbZJO/tY9Ul7kGkf1S0CWuKcCD38l8YkeH8z8QjE0GmW1gYU5S9FOnJ0" crossorigin="anonymous"></script>
</body>
</html>
As you can see the script does not work.
To be honest I am not quite sure why. I am guessing there is a problem when initializing the Tags-class. I currently do it the following:
import Tags
Tags.init();
Any suggestions what is wrong or how to correctly call the init()-function from the Tags-class?
I appreciate your replies!
In my answer I'm assuming that your question is about how to import a class from a <script> to another <script> using ECMAScript modules, which is not very clear when reading your question.
You just have to specify type="module" on the exporting script and also the importing one, then import one file from the other with its URL.
For example if you have this web site structure:
app/
├─ lib/
│ ├─ tags.js
├─ index.js
├─ index.html
The tags.js file would contain:
class Tags {
// ...
}
export default Tags;
And index.js would contain:
import Tags from './lib/tags.js';
// ...
Here is a demo, I have used data URLs as a workaround because I can't publish JavaScript files in a StackOverflow snippet, but it works exactly the same with regular <script> tags and regular URLs:
const lib = `class Tags {
static init() {
console.log('it works!');
}
}
export default Tags;`;
const libURL = createScript(lib);
const code = `import Tags from '${libURL}';
Tags.init();`;
createScript(code);
function createScript(code) {
const url = `data:application/javascript;charset=utf-8;base64,${btoa(code)}`;
const script = document.createElement('script');
script.src = url;
script.type = 'module';
document.body.appendChild(script);
return url;
}
to initiate a es6 class you would use:
const new_object = new Tags(selectElement)
you pass selectElement into your constructor function and get a new object in return.
i don't know where you are calling this code from, if you want to call it from another file you need to define it in your export default.
this way you can use the es6 import syntax.
The error export declarations may only appear at top level of a module is already explained in #Guerric P's answer.
You are calling Tags.init(); from the same file as the definition, so if you really want that you can remove:
export default Tags;
import Tags
because it's a class definition and you are calling a static function:
Tags.init(); /* default 'select[multiple]' */
it will result in no error.

How to add row in datatable - DC.js

I have a json file that loads sales data for salespeople based on the current year and the previous year.
I created a table in which I show the total sales for each year for each salesperson and, in the last row, I need to load the total for all salespeople added up. As shown in the image below:
I am using dc.dataTable to create my table.
Can you tell me if there is any way in DC.js to create a row in my table to put the total sales?
Here is my code, thank you in advance.
var vendedorTable = dc.dataTable("#Vendedores");
var url = 'http://www.json-generator.com/api/json/get/cgsUhkPSjS?indent=2';
d3.json(url).then(function(data) {
data.forEach(function(d) {
var myCrossfilter = crossfilter(data);
var all = myCrossfilter.groupAll();
dc.dataCount(".dc-data-count")
.dimension(myCrossfilter)
.group(all);
vendedorDim = myCrossfilter.dimension(function(d) {
return d.vendnm;
});
var vendedorGroup = vendedorDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
function reduceAdd(p, v) {
p.totalAno += +v.Vendas_Ano;
p.totalHomologo += +v.Vendas_Ant;
return p;
}
function reduceRemove(p, v) {
p.totalAno -= v.Vendas_Ano;
p.totalHomologo -= v.Vendas_Ant;
return p;
}
function reduceInitial() {
return {
totalAno: 0,
totalHomologo: 0,
};
}
// formatter = d3.format(".3s");
// formatter2 = d3.format(".0%");
//Fake Dimension
rank = function(p) {
return ""
};
function checkRows(d) {
if (d.value.totalAno <= 0 || isNaN(d.value.totalAno) || d.value.totalHomologo <= 0 || isNaN(d.value.totalHomologo)) {
return 0;
}
return d;
}
//vendedorTable
vendedorTable.width(500)
.height(480)
.dimension(vendedorGroup)
.group(rank)
.columns([function(d) {
d = checkRows(d);
while (d != 0) {
return d.key;
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
}
])
.sortBy(function(d) {
return d.value.totalAno
})
.order(d3.descending)
vendedorTable.on('pretransition', function(table) {
table.selectAll('td.dc-table-column')
.on('click', function(d) {
let filters = table.filters().slice();
if (filters.indexOf(d.key) === -1)
filters.push(d.key);
else
filters = filters.filter(k => k != d.key);
if (filters.length === 0)
vendedorDim.filter(null);
else
vendedorDim.filterFunction(function(d) {
return filters.indexOf(d) !== -1;
})
table.replaceFilter([filters]);
dc.redrawAll();
});
let filters = table.filters();
table.selectAll('tr.dc-table-row')
.classed('sel-rows', d => filters.indexOf(d.key) !== -1);
});
dc.renderAll();
});
$('#reset').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null)
dc.redrawAll();
});
$('#resetTable').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null)
dc.redrawAll();
});
});
<head>
<style>
.dc-table-group {
visibility: collapse;
}
tr.dc-table-row.sel-rows {
background-color: lightblue;
}
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/2.1.8/dc.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<script src="https://d3js.org/d3.v5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.js"></script>
<title>Vendedores</title>
</head>
<body>
<div class="container-fluid">
<div class="row content">
<div class="col-md-8" style="padding-left: 20px;">
<div class="row marginClass">
<h4 class="pull-left" id="Introduction"><small>Dados fictícios da empresa | Exemplo de Pesquisa
Detalhada |
</small></h4>
<h6 class="dc-data-count" style="float: left;margin-left:5px;">
<span>
<span class="filter-count"></span> selected out of
<span class="total-count"></span> records |
<a id="reset"> Reset All </a>
</span>
</h6>
</div>
<div class="col-md-6">
<br>
<a id="resetTable"> Reset</a>
<table class="table" id="Vendedores">
<thead>
<tr>
<th>Sales</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</body>
dc.js is the frontend for crossfilter, which is an in-memory database for JavaScript that is tuned for these kinds of dashboards.
You always want to add data on the database side. So the right place to look is in the crossfilter API, and here it is: crossfilter.add()
I might have just left a comment, but since you were nice enough to include running code, let's try it out!
First, let's reserve one of the vendors out of the dataset:
rows = data0.filter(d => d.vendnm === 'JOÃO LUIS');
var data = data0.filter(d => d.vendnm !== 'JOÃO LUIS');
Then, when the Add Row button is clicked, let's add that data and redraw all the associated charts:
$('#addRow').on('click', function() {
myCrossfilter.add(rows);
dc.redrawAll();
});
Notice that if you click Add Row multiple times, the sales for that vendor will double, then triple, because we are displaying an aggregated group, so that vendor gets more and more sales added in.
That's all there is to it!
var vendedorTable = dc.dataTable("#Vendedores");
// lift crossfilter and row so they are visible to addRow handler
var myCrossfilter, rows;
var url = 'http://www.json-generator.com/api/json/get/cgsUhkPSjS?indent=2';
d3.json(url).then(function(data0) {
// save Joao for later
rows = data0.filter(d => d.vendnm === 'JOÃO LUIS');
var data = data0.filter(d => d.vendnm !== 'JOÃO LUIS');
data.forEach(function(d) {
myCrossfilter = crossfilter(data);
var all = myCrossfilter.groupAll();
dc.dataCount(".dc-data-count")
.dimension(myCrossfilter)
.group(all);
vendedorDim = myCrossfilter.dimension(function(d) {
return d.vendnm;
});
var vendedorGroup = vendedorDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
function reduceAdd(p, v) {
p.totalAno += +v.Vendas_Ano;
p.totalHomologo += +v.Vendas_Ant;
return p;
}
function reduceRemove(p, v) {
p.totalAno -= v.Vendas_Ano;
p.totalHomologo -= v.Vendas_Ant;
return p;
}
function reduceInitial() {
return {
totalAno: 0,
totalHomologo: 0,
};
}
// formatter = d3.format(".3s");
// formatter2 = d3.format(".0%");
//Fake Dimension
rank = function(p) {
return ""
};
function checkRows(d) {
if (d.value.totalAno <= 0 || isNaN(d.value.totalAno) || d.value.totalHomologo <= 0 || isNaN(d.value.totalHomologo)) {
return 0;
}
return d;
}
//vendedorTable
vendedorTable.width(500)
.height(480)
.dimension(vendedorGroup)
.group(rank)
.columns([function(d) {
d = checkRows(d);
while (d != 0) {
return d.key;
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalAno * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
},
function(d) {
d = checkRows(d);
while (d != 0) {
return Number(Math.round(d.value.totalHomologo * 100) / 100).toLocaleString("es-ES", {
minimumFractionDigits: 2
}) + '€';
}
}
])
.sortBy(function(d) {
return d.value.totalAno
})
.order(d3.descending)
vendedorTable.on('pretransition', function(table) {
table.selectAll('td.dc-table-column')
.on('click', function(d) {
let filters = table.filters().slice();
if (filters.indexOf(d.key) === -1)
filters.push(d.key);
else
filters = filters.filter(k => k != d.key);
if (filters.length === 0)
vendedorDim.filter(null);
else
vendedorDim.filterFunction(function(d) {
return filters.indexOf(d) !== -1;
})
table.replaceFilter([filters]);
dc.redrawAll();
});
let filters = table.filters();
table.selectAll('tr.dc-table-row')
.classed('sel-rows', d => filters.indexOf(d.key) !== -1);
});
dc.renderAll();
});
$('#reset').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null)
dc.redrawAll();
});
$('#resetTable').on('click', function() {
vendedorTable.filter(null);
vendedorDim.filter(null)
dc.redrawAll();
});
$('#addRow').on('click', function() {
myCrossfilter.add(rows);
dc.redrawAll();
});
});
<head>
<style>
.dc-table-group {
visibility: collapse;
}
tr.dc-table-row.sel-rows {
background-color: lightblue;
}
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dc/2.1.8/dc.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<script src="https://d3js.org/d3.v5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.js"></script>
<title>Vendedores</title>
</head>
<body>
<div class="container-fluid">
<div class="row content">
<div class="col-md-8" style="padding-left: 20px;">
<div class="row marginClass">
<h4 class="pull-left" id="Introduction"><small>Dados fictícios da empresa | Exemplo de Pesquisa
Detalhada |
</small></h4>
<h6 class="dc-data-count" style="float: left;margin-left:5px;">
<span>
<span class="filter-count"></span> selected out of
<span class="total-count"></span> records |
<a id="reset"> Reset All </a>
</span>
</h6>
</div>
<div>
<a id="addRow"> Add Row </a>
</div>
<div class="col-md-6">
<br>
<a id="resetTable"> Reset</a>
<table class="table" id="Vendedores">
<thead>
<tr>
<th>Sales</th>
<th>Current Year</th>
<th>Last Year</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</body>

Filtering items with angular js

I have an array of items in form of service - as I know it's like proper way to keep data you use in different controllers.I watched tutorial and did the filtering by brands. But I have an obstacle with filtering of my Items by another parameters, such as price, length and frequency... So I have made sliders by another example but I have no idea how to tie up it with my array of Items. Please do me a favour, show how to tie up even one of my parameters, price for example.
http://angular.zxcvbn.ru
services.js:
myApp.service('ProductDataService', function() {
//sample data
var items = [
{ name:'Picachoo', id:1, price:25000, pict:'http://www.metrord.do/_internal/gxml!0/2qijkhn0ctpwx8acoz5fxkpvtmr4nbh$r05jcw5nnz5dt1u7odn7q01jm5k3ezo/screen-shot-2016-07-24-at-11-55-41-am.jpeg', len: 250, friq: 5000, brand: 'came' },
{ name:'Tortule', id:2, price:30000, pict:'https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcR2APj6_uBfhHRXLn1dZN58ZocpzMxGMFLZmuqHEU5SybKN4QAVfg', len: 250, friq: 300, brand: 'came' },
{ name:'Dragon', id:3, price:33500, pict:'https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcSJotIxkjgXgm9m3m-0FuUxN6g9fGGXmP84VDRrPZoWa-x8Dqqd', len: 350, friq: 300, brand: 'came' },
{ name:'encrypted1', id:4, price:45000, pict:'http://gaidi.ru/wp-content/uploads/2016/07/kak-pravilno-lovit-pokemonov-v-pokemon-go.jpg', len: 400, friq: 3000, brand: 'came' },
{ name:'pravilno', id:5, price:48600, pict:'http://vignette3.wikia.nocookie.net/pokemon/images/2/2e/009Blastoise_Dream.png/revision/latest?cb=20140812050618', len: 550, friq: 2000, brand: 'came' },
{ name:'images', id:6, price:30000, pict:'https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcSqywi0lMtmf1sAR-20rg0HXETMueY3H71iJP35WsdsPHGVokK41g', len: 550, friq: 1000, brand: 'bft' },
{ name:'Foxy', id:7, price:38000, pict:'http://vgtimes.ru/uploads/posts/2016-07/1468938437_pk_vulpix.png', len: 350, friq: 10000, brand: 'bft' },
{ name:'Pteradactys', id:8, price:43000, pict:'https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcRJBXypwhl8-z4IsAZokgQlqPx_vZymtENBdlPy1HhN34uODEZ5', len: 800, friq: 10000, brand: 'bft' },
{ name:'encrypted', id:9, price:35800, pict:'https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQZNKoA9LMtQHhgU4Toy7xXfzGEp6Rb4Kv6I16RgMjWO0Dnb36EFA', len: 1200, friq: 3000, brand: 'faac' },
{ name:'Jidjfj', id:10, price:14000, pict:'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRPBKrRLvhYm9y-LxwRM4Qc_psMjd_luij_04ChmmQjcrdxgmcG3w', len: 800, friq: 5000, brand: 'fors' }
];
brands = {came : true, bft : true, faac : true, fors : true} ;
this.getItems = function() {
return items;
};
this.getBrands = function() {
return brands;
};
this.maxPrice = function() {
var max;
var producto;
for(var i = 0; i < items.length-1; i++) {
for(var j = 0; j < items.length-i-1; j++){
if (producto[j] > producto[j+1]) {
max = producto[j];
producto[j] = producto[j+1];
producto[j+1] = b;
}
}
}
return max;
}
this.minPrice = function() {
var min;
var producto;
for(var i = 0; i < items.length-1; i++) {
for(var j = 0; j < items.length-i-1; j++){
if (producto[j] < producto[j+1]) {
min = producto[j];
producto[j] = producto[j+1];
producto[j+1] = b;
}
}
}
return min;
}
});
slider_price.js:
myApp.controller('priceCtrl', function($scope, ProductDataService) {
$scope.search = { price_min : '', price_max : '', amount_min : 14000, amount_max : 48600 };
});
/* Range Slider
Input with default values:
-min=0 // Min slider value
-max=100 // Max slider value
-step=1 // Steps
Output / Input model
-value-min // Default value #min
-value-max // Default value #max
example:
<slider-range min="0" max="100" step="5" value-min="scope.form.slider_value_min" value-max="scope.form.slider_value_max"></slider-range>
*/
myApp.directive('priceRange', ['$document',function($document) {
// Move slider handle and range line
var moveHandle = function(handle, elem, posX) {
$(elem).find('.handle.'+handle).css("left",posX +'%');
};
var moveRange = function(elem,posMin,posMax) {
$(elem).find('.range').css("left",posMin +'%');
$(elem).find('.range').css("width",posMax - posMin +'%');
};
return {
template: '<div class="slider horizontal">'+
'<div class="range"></div>'+
'<a class="handle min" ng-mousedown="mouseDownMin($event)"></a>'+
'<a class="handle max" ng-mousedown="mouseDownMax($event)"></a>'+
'</div>',
replace: true,
restrict: 'E',
scope:{
valueMin:"=",
valueMax:"="
},
link: function postLink(scope, element, attrs) {
// Initilization
var dragging = false;
var startPointXMin = 0;
var startPointXMax = 0;
var xPosMin = 0;
var xPosMax = 0;
var settings = {
"min" : (typeof(attrs.min) !== "undefined" ? parseInt(attrs.min,10) : 0),
"max" : (typeof(attrs.max) !== "undefined" ? parseInt(attrs.max,10) : 100),
"step" : (typeof(attrs.step) !== "undefined" ? parseInt(attrs.step,10) : 1)
};
if ( typeof(scope.valueMin) == "undefined" || scope.valueMin === '' )
scope.valueMin = settings.min;
if ( typeof(scope.valueMax) == "undefined" || scope.valueMax === '' )
scope.valueMax = settings.max;
// Track changes only from the outside of the directive
scope.$watch('valueMin', function() {
if (dragging) return;
xPosMin = ( scope.valueMin - settings.min ) / (settings.max - settings.min ) * 100;
if(xPosMin < 0) {
xPosMin = 0;
} else if(xPosMin > 100) {
xPosMin = 100;
}
moveHandle("min",element,xPosMin);
moveRange(element,xPosMin,xPosMax);
});
scope.$watch('valueMax', function() {
if (dragging) return;
xPosMax = ( scope.valueMax - settings.min ) / (settings.max - settings.min ) * 100;
if(xPosMax < 0) {
xPosMax = 0;
} else if(xPosMax > 100) {
xPosMax = 100;
}
moveHandle("max",element,xPosMax);
moveRange(element,xPosMin,xPosMax);
});
// Real action control is here
scope.mouseDownMin = function($event) {
dragging = true;
startPointXMin = $event.pageX;
// Bind to full document, to make move easiery (not to lose focus on y axis)
$document.on('mousemove', function($event) {
if(!dragging) return;
//Calculate handle position
var moveDelta = $event.pageX - startPointXMin;
xPosMin = xPosMin + ( (moveDelta / element.outerWidth()) * 100 );
if(xPosMin < 0) {
xPosMin = 0;
} else if(xPosMin > xPosMax) {
xPosMin = xPosMax;
} else {
// Prevent generating "lag" if moving outside window
startPointXMin = $event.pageX;
}
scope.valueMin = Math.round((((settings.max - settings.min ) * (xPosMin / 100))+settings.min)/settings.step ) * settings.step;
scope.$apply();
// Move the Handle
moveHandle("min", element,xPosMin);
moveRange(element,xPosMin,xPosMax);
});
$document.mouseup(function(){
dragging = false;
$document.unbind('mousemove');
$document.unbind('mousemove');
});
};
scope.mouseDownMax = function($event) {
dragging = true;
startPointXMax = $event.pageX;
// Bind to full document, to make move easiery (not to lose focus on y axis)
$document.on('mousemove', function($event) {
if(!dragging) return;
//Calculate handle position
var moveDelta = $event.pageX - startPointXMax;
xPosMax = xPosMax + ( (moveDelta / element.outerWidth()) * 100 );
if(xPosMax > 100) {
xPosMax = 100;
} else if(xPosMax < xPosMin) {
xPosMax = xPosMin;
} else {
// Prevent generating "lag" if moving outside window
startPointXMax = $event.pageX;
}
scope.valueMax = Math.round((((settings.max - settings.min ) * (xPosMax / 100))+settings.min)/settings.step ) * settings.step;
scope.$apply();
// Move the Handle
moveHandle("max", element,xPosMax);
moveRange(element,xPosMin,xPosMax);
});
$document.mouseup(function(){
dragging = false;
$document.unbind('mousemove');
$document.unbind('mousemove');
});
};
}
};
}]);
app.js:
var myApp = angular.module("filterApp", []);
myApp.controller('ExampleController', ['$scope', '$window', function($scope, $window) {
$scope.greeting = 'Hello, World!';
$scope.doGreeting = function(greeting) {
$window.alert(greeting);
};
}]);
myApp.controller('coolCtrl', function($scope) {
$scope.whoAmI = function(){
console.log("This is whoAmI function in the coolCtrl!");
};
});
myApp.controller('mainCtrl', function($scope, ProductDataService){
$scope.helloWorld = function(){
console.log("This is helloWorld function in the mailCtrl!");
};
$scope.items = ProductDataService.getItems();
$scope.brands = ProductDataService.getBrands();
$scope.refresh = function(){
location.reload();
};
$scope.showPopUpMsg = false;
$scope.openPopUp = function( text ) {
$scope.showPopUpMsg = true;
$scope.popUpMsgContent = text;
$scope.minimun = 123;
};
});
jilters.js:
myApp.filter('brandsfilter', function () {
return function(input, filter) {
var result = [];
angular.forEach(input, function (item) {
angular.forEach(filter, function (isfiltered, brand) {
if (isfiltered && brand === item.brand) {
result.push(item);
}
});
});
return result;
};
});
index.php:
<?php
require 'scripts/mail_script.php';
?>
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="apple-touch-icon" href="apple-touch-icon.png">
<!-- Place favicon.ico in the root directory -->
<link rel="stylesheet" href="styles/normalize.css">
<link rel="stylesheet" href="styles/main.css">
<link rel="stylesheet" href="styles/bootstrap.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <!-- for slider work -->
</head>
<body ng-app="filterApp" ng-controller='mainCtrl'>
<!--[if lt IE 8]>
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please upgrade your browser to improve your experience.</p>
<![endif]-->
<!-- Add your site or application content here -->
<div class="container">
<section class='top' >
<h1>Filter</h1>
<!-- //// http://embed.plnkr.co/woqn3i/ /// -->
<!-- ///////// -->
<div class="row" id='items'>
<div>
<div class="col-md-4" ><h2>params:</h2>
<div ng-controller="priceCtrl">
<p>Choose price:</p>
<p>min: <input type="number" ng-model="search.amount_min"/> $</p>
<p>max: <input type="number" ng-model="search.amount_max"/> $</p>
<slider-range min="14000" max="48600" step="100" value-min="search.amount_min" value-max="search.amount_max"></slider-range>
</div>
<hr>
<p>По названию:</p>
<p><input type="text" ng-model="price" /></p>
<p>Brand:</p>
<ul >
<li ng-repeat="(brand, value) in brands">
<input type="checkbox" ng-model="brands[brand]" /> {{brand}}
</li>
</ul>
<hr>
<!-- //// http://embed.plnkr.co/woqn3i/ /// -->
<div ng-controller="filterCtrl">
<p>length:</p>
<p>От: <input type="text" ng-model="search.price_min"/> meters</p>
<p>До: <input type="text" ng-model="search.price_max"/> meters</p>
<slider-range min="2.5" max="12" value-min="search.price_min" value-max="search.price_max"></slider-range>
<hr>
<p>friquincy:</p>
<p>Min: <input type="number" ng-model="search.amount_min"/> times</p>
<p>Max: <input type="number" ng-model="search.amount_max"/> times</p>
<slider-range min="300" max="10000" step="100" value-min="search.amount_min" value-max="search.amount_max"></slider-range>
</div>
<hr>
<!-- ///////// -->
<div class="actions"/>
<input type="button" value="Сбросить" ng-click='refresh()'>
</div>
</div>
<div class="col-md-8"><h2>______ kinds</h2>
<?php
if($success) echo '<h4 class="bg-success text-center">'.'Сообщение отправлено!' . '</h4>';
if($error_message) echo '<h4 class="bg-danger text-center">'.'Сообщение не отправлено:' . $error_message. '</h4>';
?>
<div class="row">
<!-- LOOP.-->
<div ng-repeat="item in items | filter:price | orderBy:price | brandsfilter:brands ">
<div class="col-md-4 col-sm-6 col-sx-12">
<div class="item-inner">
<div class="image-product">
<div class="caption">
<div class="box-view">
<div class="name">{{item.name}}</div>
</div>
</div>
<img src="{{item.pict}}" alt="{{item.name}}" title="{{item.name}}" class="img-responsive">
<p class="price"><span class="price">Price: {{item.price}} $.</span></p>
<p class="description">{{item.name}} - just another piece of information, first preporty is {{item.len}} m. <br>another is: {{item.friq}} per day. </p>
</div>
</div>
</div><!-- col -->
</div> <!-- ng-repeat -->
</div> <!-- row -->
</div>
</div> <!-- mainCtrl -->
</section>
</div>
<div class="panel-footer">
<script src="vendor/angular.js"></script>
<script src="scripts/app.js"></script>
<script src="scripts/services.js"></script>
<script src="scripts/filters.js"></script>
<script src="scripts/slider.js"></script>
<script src="scripts/slider_price.js"></script>
<script src="vendor/jquery.js"></script>
<script src="vendor/bootstrap.js"></script>
<!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
</div>
</body>
</html>
AngularJS built-in filter which you already used supports multiple keywords filter see, you only need to implement comparator function to fulfill your needs.
First, change your filter in template to
<div ng-repeat="item in items | filter:myFilters:myComparator | orderBy:price">
then inside your filterCtrl you need to define myFilters and myComparator
$scope.myFilters = {price: 4000, brand: 'abc'};
$scope.myComparator = function(actual, expected) {
if (actual == parseInt(actual)) {
return actual > expected;
}
else {
return actual == expected;
}
}
Inside myComparator you can customise how you want to filter it (exact match, arithmetic comparison or partial match, just remember to return Boolean.
Just update $scope.myFilters whenever your filter keywords changed, the result will be updated in next digest cycle.

How to show first youtube video in iframe and other in thumbnail?

Hi I want to show only the first video in iframe while other in thumbnail.
Here is my code you can run it on localhost.If you have any solution then please reply me.
index.php file
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
<head>
<meta charset="UTF-8">
<title>youtube Channel Videos</title>
<style>
body{
background: #f4f4f4;
font-family: "Arial" sans-serif;
font-size: 14px;
color: #666;
}
#container{
width: 800px;
overflow: auto;
margin: auto;
background: #fff;
padding: 15px;
}
.anc{
padding: 2px 6px;
background: #EFF7FF;
color: #069;
border: 1px solid #C2D9EF;
margin: 0px 0px 0px 5px;
-moz-border-radius: 1px;
-webkit-border-radius: 1px;
text-decoration: none;
text-align: center;
}
</style>
<!-- <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">-->
<script src="js/jquery.min.js"></script>
<script type="text/javascript" src="http://www.youtube.com/player_api"></script>
<!-- <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>-->
<script src="js/script.js"></script>
</head>
<body>
<?php
// put your code here
?>
<div id="container">
<h1>Youtube Videos</h1>
<ul id="results">
</ul>
<div id="page" style="padding-top: 15px;padding-left: 42px;"></div>
</div>
<script>
players = new Array();
//alert($("iframe.yt_players"));
function onYouTubeIframeAPIReady() {
var temp = $("iframe.yt_players");
for (var i = 0; i < temp.length; i++) {
var t = new YT.Player($(temp[i]).attr('id'), {
events: {
'onStateChange': onPlayerStateChange
}
});
players.push(t);
}
}
window.onload = setTimeout(onYouTubeIframeAPIReady, 10000);
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING) {
var temp = event.target.a.src;
var tempPlayers = $("iframe.yt_players");
for (var i = 0; i < players.length; i++) {
if (players[i].a.src != temp) players[i].stopVideo();
}
}
}
</script>
</body>
</html>
script.js file
function tplawesome(template, data) {
// initiate the result to the basic template
res = template;
// for each data key, replace the content of the brackets with the data
for(var i = 0; i < data.length; i++) {
res = res.replace(/\{\{(.*?)\}\}/g, function(match, j) { // some magic regex
return data[i][j];
});
}
return res;
}
var channelName= "TechGuyWeb";
$(document).ready(function(){
$.get("https://www.googleapis.com/youtube/v3/channels",{
part: 'contentDetails',
forUsername: channelName,
key:'AIzaSyBX94DoCYdtIwALVPfqSVar6izj3wCJ1M4'},
function(data){
console.log(data);
$.each(data.items,function(i, item){
var pid = item.contentDetails.relatedPlaylists.uploads;
//console.log(pid);
getVids(pid);
});
}
);
//var pid="10thStreetPreschool";
// function getvids(pid){
// $.get("https://www.googleapis.com/youtube/v3/playlistItems",{
// part: 'snippet',
// maxResults: 10,
// playlistId:pid,
// key:'AIzaSyBX94DoCYdtIwALVPfqSVar6izj3wCJ1M4'},
// function(data){
// var output;
// $.each(data.items,function(i, item){
// console.log(data);
// var v_id = item.snippet.resourceId.videoId;
// //alert(item.snippet.resourceId.videoId);
// //var video_title = item.snippet.title;
// //output= '<li>'+video_title+'</li>';
// $.get("item.html",function(data){
// $('#results').append(tplawesome(data, [{"title":item.snippet.title,"videoid":item.snippet.resourceId.videoId,"description":item.snippet.description}]));
// getcount(v_id);
// });
// //$('#results').append(output);
// });
// }
// );
// }
function getVids(pid, pageToken){
var data = {
part: 'snippet',
maxResults: 10,
playlistId: pid,
key: 'AIzaSyBX94DoCYdtIwALVPfqSVar6izj3wCJ1M4'
}
try{
if(pageToken){
data["pageToken"] = pageToken;
}
}catch(err){
}
$.get(
"https://www.googleapis.com/youtube/v3/playlistItems", data,
function(data){
var output;
$('#results').html("");
$.each(data.items,function(i, item){
console.log(data);
var v_id = item.snippet.resourceId.videoId;
// var total_results =data.pageInfo.totalResults;
// console.log(total_results);
$.get("item.html",function(data){
$('#results').append(tplawesome(data, [{"title":item.snippet.title,"videoid":item.snippet.resourceId.videoId,"description":item.snippet.description}]));
getcount(v_id);
});
//$('#results').append(output);
});
$('#page').html("");
try{
if(data.prevPageToken){
$("#page").append('<span><a class="anc" href="javascript:void(0);" onclick="getVids(\'' + pid + '\', \'' + data.prevPageToken + '\');">« Previous<a/></span>');
}
}catch(err){
}
try{
if(data.nextPageToken){
$("#page").append('<span><a class="anc" href="javascript:void(0);" onclick="getVids(\'' + pid + '\', \'' + data.nextPageToken + '\');">Next »<a/></span>');
}
}catch(err){
}
});
}
function getcount(v_id){
$.get("https://www.googleapis.com/youtube/v3/videos",{
part: 'statistics',
id: v_id,
key:'AIzaSyBX94DoCYdtIwALVPfqSVar6izj3wCJ1M4'},
function(data){
$.each(data.items,function(i, item){
var views = item.statistics.viewCount;
//console.log(views);
$('#'+v_id).append(views);
});
}
);
}
});
function getVids(pid, pageToken){
var data = {
part: 'snippet',
maxResults: 10,
playlistId: pid,
key: 'AIzaSyBX94DoCYdtIwALVPfqSVar6izj3wCJ1M4'
}
try{
if(pageToken){
data["pageToken"] = pageToken;
}
}catch(err){
}
$.get(
"https://www.googleapis.com/youtube/v3/playlistItems", data,
function(data){
var output;
$('#results').html("");
$.each(data.items,function(i, item){
console.log(data);
var v_id = item.snippet.resourceId.videoId;
//alert(item.snippet.resourceId.videoId);
//var video_title = item.snippet.title;
//output= '<li>'+video_title+'</li>';
$.get("item.html",function(data){
$('#results').append(tplawesome(data, [{"title":item.snippet.title,"videoid":item.snippet.resourceId.videoId,"description":item.snippet.description}]));
getcount(v_id);
});
//$('#results').append(output);
});
$('#page').html("");
try{
if(data.prevPageToken){
$("#page").append('<span><a class="anc" href="javascript:void(0);" onclick="getVids(\'' + pid + '\', \'' + data.prevPageToken + '\');">« Previous<a/></span>');
}
}catch(err){
}
try{
if(data.nextPageToken){
$("#page").append('<span><a class="anc" href="javascript:void(0);" onclick="getVids(\'' + pid + '\', \'' + data.nextPageToken + '\');">Next »<a/></span>');
}
}catch(err){
}
});
}
function getcount(v_id){
$.get("https://www.googleapis.com/youtube/v3/videos",{
part: 'statistics',
id: v_id,
key:'AIzaSyBX94DoCYdtIwALVPfqSVar6izj3wCJ1M4'},
function(data){
$.each(data.items,function(i, item){
var views = item.statistics.viewCount;
console.log(views);
$('#'+v_id).append(views);
});
}
);
}
item.html file
<div class="item" style="padding-bottom: 30px;">
<iframe id="player{{videoid}}" class="yt_players" src="http://www.youtube.com/embed/{{videoid}}?rel=0&enablejsapi=1;showinfo=0;&wmode=Opaque" width="560" height="315" frameborder="0" allowfullscreen></iframe>
<div style="margin-bottom: -22px;margin-top: -20px;"><h2 style="font-size:18px;">{{title}}</h2></div>
<div style="margin-bottom: -18px;"><h5 style="font-size:16px;">{{description}}</h5> </div>
<div><h5 style="font-size:14px;margin-top: -5px;">Total Views: <span id="{{videoid}}"></span></h5> </div>
</div>

Categories