Trying to count SharePoint List Values with JavaScript - javascript

Hello stack overflow community...
Thanks for all of the help that you have provided so far even though I have never posted on this site. I am a beginner... so that means most of the stuff that I have gotten to work has come after trying to shove a square peg into a round hole too many times to count until finally the edges are worn off enough that it actually fits...
Anyway... due to the Today() issue with SharePoint and the need to base data comparison against the current date/time I have been struggling to write my own code and display the data as I would like to in the SharePoint site that I have access too.
So far I have everything working as intended with one little flaw...
I cannot figure out how to count values even though I can make comparisons between two values. I believe it has something to do with how data is being retrieved from the SharePoint list rows and appended to the HTML table.
Relevant sections of code are as follows:
$(document).ready(function () {
$().SPServices({
operation: "GetListItems",
async: false,
CAMLRowLimit: 20,
listName: "Announcements",
completefunc: FirstFunc
});
});
function FirstFunc(xData, Status) {
var index = 0;
$documentListtable = $("#tableFirstFunc");
$(xData.responseXML).find("z\\:row, row").each(function () {
var LOTOSPLink =$(this).attr("ows_LOTODocLink");
var _Title = $(this).attr("ows_Title");
var ahref = "<a href='" + LOTOSPLink + "'>";
var anchor = "</a>"
var Titles = ahref + _Title + anchor
//Start of AReview
var _AReview = $(this).attr("ows_AReview");
var astartDateTime = $(this).attr("ows_AReview");
var astartDate = $(this).attr("ows_AReview").split(" ")[0];
var astartTime = $(this).attr("ows_AReview").split(" ")[1];
var astartDateParts = astartDate.split("-");
var aSPDYear = astartDateParts[0];
var aSPDMonth = astartDateParts[1];
var aSPDDay = astartDateParts[2];
var aSPDJoin = aSPDMonth+'/'+aSPDDay+'/'+aSPDYear;
var astartTimeParts = astartTime.split(":");
var aSPTHour = astartTimeParts[0];
var aSPTMin = astartTimeParts[1];
var aSPTSec = astartTimeParts[2];
//Combine SharePoint Date & Time split parts back together in JS Date Object
//format and than convert to millisecons to compare dates
var aReviewGraphic = ""
if(aSPDTValue === 18000000) {
aReviewGraphic="<img src="sites/Somesite/NAGlassyButton20.png>";
}
else if(aSPDTValue >= firstDCMonth && aSPDTValue < lastDCMonth) {
aReviewGraphic="<img src="/sites/Somesite/GreenButtNew20.png>";
}
else if(aSPDTValue >= firstDCYear && aSPDTValue < firstDCMonth) {
aReviewGraphic="<img src="/sites/Somesite//GreenButtOld20.png>";
}
else if(aSPDTValue < firstDCYear) {
aReviewGraphic="<img src="/sites/Somesite/RedButt20.png>";
}
var $row = $("#templates").find(".row-template").clone();
$row.find(".Titles").html(Titles);
$row.find(".aReviewGraphic").html(aReviewGraphic);
$row.find(".bReviewGraphic").html(bReviewGraphic);
$row.find(".cReviewGraphic").html(cReviewGraphic);
$row.find(".dReviewGraphic").html(dReviewGraphic);
$row.find(".NewModiDReviewGraphic").html(NewModiDReviewGraphic);
$documentListtable.append($row);
});
}
I am changing the graphics in the tables as intended, the data is being displayed as desired... but I cannot figure out how to perform a count. It seems like the rows are being read one at a time and being put into the HTML table one after the other and that all comparisons are being done row by row. I say that because my alert(messages) are being triggered for each row of data pulled in from the sharepoint list.
Is there a way to store this data in an array locally... surely there is some way to do this but I am new enough to this that I don't even know the right questions to ask...
Also the 18000000 in the if statement is the 1/1/1970 test date that I am using to currently test with as I found that any fields that were blank in the sharepoint list would cause the query to quit returning any rows after that. My solution was to use the 1/1/1970 as the default value and use it the same as leaving the field blank. I am sure that this is a crude method to work a round a problem that is easy to fix but it was all I could come up with.
Any help would be appreciated...
Steve

I try to understand... My suggestion is to store all your html into a variable and then inject the code into the table.
// somewhere you should have your HTML code
// <table id="templates"></table>
$(document).ready(function () {
$().SPServices({
operation: "GetListItems",
async: false,
CAMLRowLimit: 20,
listName: "Announcements",
completefunc: FirstFunc
});
});
function FirstFunc(xData, Status) {
var index = 0;
$documentListtable = $("#tableFirstFunc");
// create a variable where to store the html code
var htmlData = "";
// go thru the data received by the query
$(xData.responseXML).find("z\\:row, row").each(function () {
// we look at one row
var LOTOSPLink =$(this).attr("ows_LOTODocLink");
var _Title = $(this).attr("ows_Title");
var ahref = "<a href='" + LOTOSPLink + "'>";
var anchor = "</a>"
var Titles = ahref + _Title + anchor
//Start of AReview
var _AReview = $(this).attr("ows_AReview");
var astartDateTime = $(this).attr("ows_AReview");
var astartDate = $(this).attr("ows_AReview").split(" ")[0];
var astartTime = $(this).attr("ows_AReview").split(" ")[1];
var astartDateParts = astartDate.split("-");
var aSPDYear = astartDateParts[0];
var aSPDMonth = astartDateParts[1];
var aSPDDay = astartDateParts[2];
var aSPDJoin = aSPDMonth+'/'+aSPDDay+'/'+aSPDYear;
var astartTimeParts = astartTime.split(":");
var aSPTHour = astartTimeParts[0];
var aSPTMin = astartTimeParts[1];
var aSPTSec = astartTimeParts[2];
//Combine SharePoint Date & Time split parts back together in JS Date Object
//format and than convert to millisecons to compare dates
var aReviewGraphic = "";
// I don't understand why you use this variable that hasn't been initialized...
if (aSPDTValue === 18000000) {
aReviewGraphic='<img src="sites/Somesite/NAGlassyButton20.png>';
}
else if(aSPDTValue >= firstDCMonth && aSPDTValue < lastDCMonth) {
aReviewGraphic='<img src="/sites/Somesite/GreenButtNew20.png>';
}
else if(aSPDTValue >= firstDCYear && aSPDTValue < firstDCMonth) {
aReviewGraphic='<img src="/sites/Somesite//GreenButtOld20.png>';
}
else if(aSPDTValue < firstDCYear) {
aReviewGraphic='<img src="/sites/Somesite/RedButt20.png>';
}
htmlData += '<tr><td class="Titles">'+Titles+'</td><td class="aReviewGraphic">'+aReviewGraphic+'</td><td class="bReviewGraphic">'+bReviewGraphic+'</td><td class="cReviewGraphic">'+cReviewGraphic+'</td><td class="dReviewGraphic">'+dReviewGraphic+'</td><td class="NewModiDReviewGraphic">'+NewModiDReviewGraphic+'</td></tr>';
// you can increment your index if you want
index++;
});
alert("There are "+index+" rows");
// add the HTML data into the table
$documentListtable.append(htmlData);
}

Related

How can I make my Google Apps Script function work on cell input?

I have a project that I've been working on for a bit. I've received some excellent help here, and I think I'm almost done and just need one more bit of help to get it working.
The script looks at a Google Sheet and takes a place name entered in Column A and uses the Google Places API to find requested information about it (address, phone number, etc.)
The last bit of help that I need will be able to implement the cell input component. The last user to help me said that
function writeToSheet(){
var ss = SpreadsheetApp.getActiveSheet();
var data = COMBINED2("Food");
var placeCid = data[4];
var findText = ss.createTextFinder(placeCid).findAll();
if(findText.length == 0){
ss.getRange(ss.getLastRow()+1,1,1, data.length).setValues([data])
}
}
would be able use TextFinder to check if the place url exists in the Sheet. If the result of TextFinder is 0, it will call COMBINED2() to get the place information and populate the Sheet with writeToSheet()
They noted that
You can use a cell input in your COMBINED2 by using
ss.getRange(range).getValue()
Not having a coding background, I have been able to stitch most of this together on my own, but I could use a bit of help in adding that capability to my code. Any help or guidance would be great.
Here is the code in full:
// This location basis is used to narrow the search -- e.g. if you were
// building a sheet of bars in NYC, you would want to set it to coordinates
// in NYC.
// You can get this from the url of a Google Maps search.
const LOC_BASIS_LAT_LON = "40.74516247433546, -73.98621366765816"; // e.g. "37.7644856,-122.4472203"
function COMBINED2(text) {
var API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx';
var baseUrl = 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json';
var queryUrl = baseUrl + '?input=' + text + '&inputtype=textquery&key=' + API_KEY + "&locationbias=point:" + LOC_BASIS_LAT_LON;
var response = UrlFetchApp.fetch(queryUrl);
var json = response.getContentText();
var placeId = JSON.parse(json);
var ID = placeId.candidates[0].place_id;
var fields = 'name,formatted_address,formatted_phone_number,website,url,types,opening_hours';
var baseUrl2 = 'https://maps.googleapis.com/maps/api/place/details/json?placeid=';
var queryUrl2 = baseUrl2 + ID + '&fields=' + fields + '&key='+ API_KEY + "&locationbias=point:" + LOC_BASIS_LAT_LON;
if (ID == '') {
return 'Give me a Google Places URL...';
}
var response2 = UrlFetchApp.fetch(queryUrl2);
var json2 = response2.getContentText();
var place = JSON.parse(json2).result;
var weekdays = '';
place.opening_hours.weekday_text.forEach((weekdayText) => {
weekdays += ( weekdayText + '\r\n' );
} );
var data = [
place.name,
place.formatted_address,
place.formatted_phone_number,
place.website,
place.url,
weekdays.trim()
];
return data;
}
function getColumnLastRow(range){
var ss = SpreadsheetApp.getActiveSheet();
var inputs = ss.getRange(range).getValues();
return inputs.filter(String).length;
}
function writeToSheet(){
var ss = SpreadsheetApp.getActiveSheet();
var data = COMBINED2("Food");
var placeCid = data[4];
var findText = ss.createTextFinder(placeCid).findAll();
if(findText.length == 0){
ss.getRange(ss.getLastRow()+1,1,1, data.length).setValues([data])
}
}
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu("Custom Menu")
.addItem("Get place info","writeToSheet")
.addToUi();
}
Update
Here is a link to a Shared Sheet in case anyone wants to work on it with me.
https://docs.google.com/spreadsheets/d/1KGsk6nkin1CUgpjfHU_AdhF17T_Eh41_g4MLb1CG_Tk/edit#gid=2100307022
Here is what I might not have articulated properly.
I wanted to be able to enter the names of places in Column A
Then, I want to be able to run the function with the custom menu feature. If TextFinder does not find the Place URL for the given place, it will look up the data and write it to the Sheet.
I wanted to limit the number of API calls with this and to make sure the data was written to the Sheet so that it does not need to be pulled each time the Sheet is reopened.
Finished Product
Big thanks to Lamblichus for sticking this out with me. I hope this helps other people some day.
Here is the finished code:
// This location basis is used to narrow the search -- e.g. if you were
// building a sheet of bars in NYC, you would want to set it to coordinates
// in NYC.
// You can get this from the url of a Google Maps search.
const LOC_BASIS_LAT_LON = "ENTER_GPS_COORDINATES_HERE"; // e.g. "37.7644856,-122.4472203"
function COMBINED2(text) {
var API_KEY = 'ENTER_API_KEY_HERE';
var baseUrl = 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json';
var queryUrl = baseUrl + '?input=' + text + '&inputtype=textquery&key=' + API_KEY + "&locationbias=point:" + LOC_BASIS_LAT_LON;
var response = UrlFetchApp.fetch(queryUrl);
var json = response.getContentText();
var placeId = JSON.parse(json);
var ID = placeId.candidates[0].place_id;
var fields = 'name,formatted_address,formatted_phone_number,website,url,types,opening_hours';
var baseUrl2 = 'https://maps.googleapis.com/maps/api/place/details/json?placeid=';
var queryUrl2 = baseUrl2 + ID + '&fields=' + fields + '&key='+ API_KEY + "&locationbias=point:" + LOC_BASIS_LAT_LON;
if (ID == '') {
return 'Give me a Google Places URL...';
}
var response2 = UrlFetchApp.fetch(queryUrl2);
var json2 = response2.getContentText();
var place = JSON.parse(json2).result;
var weekdays = '';
if (place.opening_hours && place.opening_hours.weekday_text) {
place.opening_hours.weekday_text.forEach((weekdayText) => {
weekdays += ( weekdayText + '\r\n' );
} );
}
var data = [
place.name,
place.formatted_address,
place.formatted_phone_number,
place.website,
place.url,
weekdays.trim()
];
return data;
}
function writeToSheet() {
const sheet = SpreadsheetApp.getActiveSheet();
const FIRST_ROW = 2;
const sourceData = sheet.getRange(FIRST_ROW, 1, sheet.getLastRow()-FIRST_ROW+1, 6)
.getValues().filter(row => String(row[0]));
for (let i = 0; i < sourceData.length; i++) {
const sourceRow = sourceData[i];
if (sourceRow[4] === "") {
const text = sourceRow[0];
const data = COMBINED2(text);
sheet.getRange(FIRST_ROW+i, 2, 1, data.length).setValues([data]);
}
}
}
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu("Custom Menu")
.addItem("Get place info","writeToSheet")
.addToUi();
}
Desired goal:
If I understand you correctly, for each value in column A, you want to retrieve some related data from Maps API and paste it to columns B-F, if column E is not currently populated.
Issues:
You are only providing the last value from column A to COMBINED2, but you want to loop through all values in column A and fetch the desired information for all of them (as long as the Place URL -column E- is not already populated).
If you want to avoid calling Maps API if the Place URL is not populated, using TextFinder after calling Maps API doesn't make sense; you don't limit your calls to the API if you do that. If you just want to check whether the Place URL column is populated, I'd suggest checking whether the cell is empty or not, and calling Maps API if it's empty.
Proposed workflow:
Retrieve all values from the sheet, including not just column A but also E (for practical purposes, all 6 columns are fetched in the sample below, since it can be done in one call), using Range.getValues().
Iterate through the rows (for example, using for), and for each row, check that the cell in E is populated.
If the cell in E (Place URL) is empty, use the value in A as the parameter for COMBINED2 and write the resulting data to columns B-F, as you are currently doing.
Code sample:
function writeToSheet() {
const sheet = SpreadsheetApp.getActiveSheet();
const FIRST_ROW = 2;
const sourceData = sheet.getRange(FIRST_ROW, 1, sheet.getLastRow()-FIRST_ROW+1, 6)
.getValues().filter(row => String(row[0]));
for (let i = 0; i < sourceData.length; i++) {
const sourceRow = sourceData[i];
if (sourceRow[4] === "") {
const text = sourceRow[0];
const data = COMBINED2(text);
sheet.getRange(FIRST_ROW+i, 2, 1, data.length).setValues([data]);
}
}
}
Update:
For names in which Places API doesn't return opening_hours, consider checking if this exists first:
function COMBINED2(text) {
// ... REST OF YOUR FUNCTION ...
var weekdays = '';
if (place.opening_hours && place.opening_hours.weekday_text) {
place.opening_hours.weekday_text.forEach((weekdayText) => {
weekdays += ( weekdayText + '\r\n' );
} );
}
var data = [
place.name,
place.formatted_address,
place.formatted_phone_number,
place.website,
place.url,
weekdays.trim()
];
return data;
}
By using the event trigger function...
function onEdit(e){
SpreadsheetApp.getActiveSheet().getRange(insert your range in A1 format).setValue("anything you want to add into the cell")
}
function onEdit(e){
var ss = SpreadsheetApp.getActiveSheet();
var data = COMBINED2("Food");
var placeCid = data[4];
var findText = ss.createTextFinder(placeCid).findAll();
if(findText.length == 0){
ss.getRange(ss.getLastRow()+1,1,1, data.length).setValues([data])
}
}
u need to specifically tell google apps script that the function is as such so that your function will execute when a event object known as e has happened.
You can read more about it on Simple Triggers

Google Sheets App Script timing out and time based trigger not running

Below is all of my code from a function that I have been working on for a while. Essentially I am trying to create a load of class analysis packs (I am a teacher) and print a google sheet as a PDF and then change a drop down (effectively changing the page and data) and then print again until all of the class codes in the drop down have been completed. The function works really well but the issue I have is that it will take longer than 6 mins to run as there are about 150 packs to create. I have looked into triggers and created a time based trigger which should start a few minutes after it has timed out. It seems to successfully create the trigger but the trigger never actually runs. Is this the correct approach? If so can anybody spot why its not working? Any feedback would be amazing as this has been driving me crazy!
function CreateClassPacks() {
SpreadsheetApp.getUi() // Or DocumentApp or FormApp
var startTime= (new Date()).getTime();
var REASONABLE_TIME_TO_WAIT = 100000
var MAX_RUNNING_TIME = 340000
// Getting the date and putting it into the format we want
var d= new Date();
var dateStamp = d.getDate()+"/"+d.getMonth()+"/"+d.getYear();
// Getting a token which will give me the authorisation I need
var request = {
"method": "GET",
"headers":{"Authorization": "Bearer "+ScriptApp.getOAuthToken()},
"muteHttpExceptions": true
};
// This is the key for the spreadsheet I am working on and then it gets fetched
var ss = SpreadsheetApp.getActiveSpreadsheet();
var getKeys = ss.getSheetByName("Settings");
var mainSSKey= getKeys.getRange("B1").getValue();
// Key for the folder we will save the documents into
var folderCPKey = getKeys.getRange("B2").getValue();
var foldersave=DriveApp.getFolderById(folderCPKey);
var fetch='https://docs.google.com/spreadsheets/d/'+mainSSKey+'/export?format=pdf&size=A4&portrait=false'
// This section gets all of the class codes from whichever sheet we choose.
// The first variable will need changing to whichever number sheet holds the codes.
var classCodeSheetNum = 0
var classCodeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[classCodeSheetNum]
var maxRowNum = classCodeSheet.getLastRow()-1;
// This variable must contain the correct column for the class codes
var dataRange = classCodeSheet.getRange(1, 1, maxRowNum, 1);
var data = dataRange.getValues();
Logger.log(data)
// This must be the sheet number for the class analysis packs
var sheetNum = 4
var newTrig = false
// This will loop through my data variable which contains all the class codes
for (var r=0; r<(data.length)-1; r++) {
for (i in data[0]) {
var scriptProperties = PropertiesService.getScriptProperties();
var startRow= scriptProperties.getProperty('start_row');
var currTime = (new Date()).getTime();
if(currTime - startTime >= MAX_RUNNING_TIME) {
if (newTrig == false){
ScriptApp.newTrigger("CreateClassPacks")
.timeBased()
.at(new Date(currTime+REASONABLE_TIME_TO_WAIT))
.create();
newTrig = true
break;
}
} else {
// This sets the value of A2 on the analysis sheet to the value from the data structure
SpreadsheetApp.getActiveSpreadsheet().getSheets()[sheetNum].getRange('O1').setValue(data[r][i]);
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getSheets()[sheetNum];
// This gets the value from A2 and sorts out the name of the file
var classCode = data[r][i]
var name = classCode + " " + dateStamp + ".pdf";
// This checks if the file already exists which will hopefully fix any timeout issues
var file = DriveApp.getFilesByName(name)
var chk = file.hasNext()
if (chk === false) {
// This hides all the sheets except for the one I am printing
for(var w=0; w< sheetNum;w++)
{
sheet = source.getSheets()[w];
sheet.hideSheet();
}
// This PDFs the page and has a timeout delaying the access requests so I don't get the annoying errors
var pdf = UrlFetchApp.fetch(fetch, request);
pdf = pdf.getBlob().setName(name);
Utilities.sleep(4000);
var file = foldersave.createFile(pdf)
// This shows all the sheets that I previously hid
for(var q=0; q< sheetNum;q++)
{
sheet = source.getSheets()[q];
sheet.showSheet();
}
}
}
}
}
}
This shows that the trigger seems to be created even though it doesn't run the function again
Maybe I'm missing something here but I think your code could be a lot quicker. For one thing create the var ss=SpreadsheetApp.getActive() and then use ss everywhere else. All create var allSheets=ss.getSheets() and then use allSheets[i] instead of 'ss.getSheets()[i]`. That section for i in data[0] makes no sense to me. The data is one column wide. All I would hide all of the sheets before the loop and then if necessary show the one that I'm printing if you have to. Hiding and showing sheets takes time. Try not to do it. I have gone through the code a bit but admittedly I don't have any context so I doubt that it runs. But I tried to take as much out of the loop as possible and you should too. You may find that you can get it to run in the allotted time.
function CreateClassPacks() {
var dateStamp=Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "dd/MM/yyyy")
var ss=SpreadsheetApp.getActive();
var getKeys=ss.getSheetByName("Settings");
var mainSSKey=getKeys.getRange("B1").getValue();
var folderCPKey=getKeys.getRange("B2").getValue();
var foldersave=DriveApp.getFolderById(folderCPKey);
var fetch='https://docs.google.com/spreadsheets/d/'+mainSSKey+'/export?format=pdf&size=A4&portrait=false'
var classCodeSheetNum=0;
var classCodeSheet=SpreadsheetApp.getActiveSpreadsheet().getSheets()[classCodeSheetNum]
var maxRowNum=classCodeSheet.getLastRow()-1;
var dataRange=classCodeSheet.getRange(1, 1, maxRowNum, 1);
var data=dataRange.getValues();
var sheetNum=4;
var newTrig=false;
var allSheets=ss.getSheets();
for(var i=0;i<allSheets.length;i++){
allSheets[i].hideSheet();
}
var srcrng=allSheets[sheetNum].getRange('O1');
var sheet=allSheets()[sheetNum];
for (var r=0;r<data.length-1;r++){
srcrng.setValue(data[r][0]);
var classCode = data[r][i]
var name=classCode + " " + dateStamp + ".pdf";
var file=DriveApp.getFilesByName(name);
var chk=file.hasNext()
sheet.showSheet();
var pdf = UrlFetchApp.fetch(fetch, request);
pdf = pdf.getBlob().setName(name);
var file = foldersave.createFile(pdf);
sheet.hideSheet();
}
}

Working with Localstorage for put content in table (JQuery)

I have a big problem working with this.
I have a table in my html, in my js I'm using localstore (I have never used that before)
I insert a new row, and it is stored with localstore, I create a JSON.
For putting the ID of the raw, I just get the length of my localstorage.
For example, I have 3 rows, with IDs 1, 2 and 3.
If I decide to delete one, we can say the number 2, I can delete it, yeah, but the next time when I create a new raw I'll have the id = 2.
why?, because I use localstorage.length+1 for putting the id, so... If I had 3 before, the next time I'll get a 3, I'll replace my content where ID = 3.
what can I do for avoid that mistake?
my JS is this
crearTabla(tablastorage)
$("#btnNuevo").on('click',function(){
$("#mymodal1").modal("show");
$('#btnGuardar').data('evento','crear');
});
$("#btnCargar").on('click',function(){
crearTabla(tablastorage)
});
$("#btnGuardar").on('click',function(){
if($(this).data('evento') == "crear"){
Crear();
$('input:text').val('');
}
else{
Modificar();
}
$("#mymodal1").modal("hide");
});
function crearTabla(data){
$("#tabla").empty();
$.each(data, function(index, val){
var temp = JSON.parse(val);
var $tr = $("<tr/>");
var $tdID = crearTD(temp.id);
var $tdMatricula = crearTD(temp.matricula);
var $tdNombre = crearTD(temp.nombre);
var $tdSexo = crearTD(temp.sexo);
var $tdAccion = crearAccion(temp);
$tr.append($tdID, $tdMatricula, $tdNombre, $tdSexo, $tdAccion);
$("#tabla").append($tr);
$('input:text').val('');
})
}
function Crear(){
var $tr = $("<tr/>");
var $tdID = crearTD(tablastorage.length+1);
var $tdMatricula = crearTD($("#matricula").val());
var $tdNombre = crearTD($("#nombre").val());
var $tdSexo = crearTD($("#sexo").val());
var JSon = {
id:tablastorage.length+1,
matricula:$("#matricula").val(),
nombre:$("#nombre").val(),
sexo:$("#sexo ").val()
}
if($('#matricula').val()=='' || $('#nombre').val()=='' || $('#sexo').val()==''){
alert("Uno o mas campos vacios");
}
else{
tablastorage.setItem(tablastorage.length, JSON.stringify(JSon))
var $tdAccion = crearAccion(JSon);
crearTabla(tablastorage)
$('input:text').val('');
}
};
function crearTD(texto){
return $("<td/>").text(texto);
};
function crearAccion(objeto){
var $td = $("<td/>");
var $div = $("<div/>",{
class:'btn-group',
role:'group'
});
var $btnElminar = $("<button/>",{
class:'btn btn-danger eliminar'
}).html("<i class='glyphicon glyphicon-remove'></i>"
).data('elemento',objeto);
var $btnModificar = $("<button/>",{
class:'btn btn-info modificar'
}).html("<i class='glyphicon glyphicon-pencil'></i>"
).data('elemento',objeto);
$div.append($btnElminar, $btnModificar)
return $td.append($div);
};
$("#tabla").on('click','.eliminar',function(event){
console.log($(this).data('elemento').id)
tablastorage.removeItem($(this).data('elemento').id-1)
crearTabla(tablastorage)
});
$("#tabla").on('click','.modificar',function(event){
index = $(this).data('elemento').id-1;
var $elemento = $(this).data('elemento');
$('#btnGuardar').data('evento','modificar');
$('#id').val($elemento.id);
$('#matricula').val($elemento.matricula);
$('#nombre').val($elemento.nombre);
$('#sexo').val($elemento.sexo);
$("#mymodal1").modal("show");
});
and my html have this code:
http://notes.io/wAYL
Two extra things.
1. Sorry for my bad english, If I've made a mistake is because I speak spanish, not english all the time, I need to improve my skills with the languague.
2. Also because I don't know how to put the code here. I just tried and I faild so many times.
<-- Please don't erase this -->
What i usually do is store whole arrays in one storage key as JSON.
When you load page you get whole array using something like:
var data = JSON.parse( localStorage.getItem('tableData') || "[]");
$.each(data, function(_, item){
// append html to table for each item
});
Then in your Crear() you would push the new item into the array, and store the whole array
var JSon = {
id: +new Date(),
matricula:$("#matricula").val(),
nombre:$("#nombre").val(),
sexo:$("#sexo ").val()
}
data.push(JSon);
localStorage.setItem('tableData', JSON.stringify(data));
Similar to remove an item , splice() the array to remove it from main array and store again.
One suggestion for ID is use current timestamp

Keep Javascript constant the same after function is recalled

I am trying to create a dynamic list so when the user performs a search it will repopulate the list. The problem is that I can't seem to make an immutable constant to store the original div content. Every time the function get's called this variable gets reinitialized.
Is there a way to achieve this without using cookies ? Any help is sincerely appreciated. The code is not complete because I couldn't get passed this step but if you think I am totally heading toward the wrong direction please let me know.
const originalList = document.getElementById('patientList').getElementsByTagName('li');
frozen = Object.freeze(originalList);
<script>
const originalList = document.getElementById('patientList').getElementsByTagName('li');
frozen = Object.freeze(originalList);
var newList = '';
var found = false;
function filterPatients(){
var searchQuery = document.getElementById('search');
var query = searchQuery.value;
var listContainer = document.getElementById('patientList');
var patientList = listContainer.getElementsByTagName('li');
for (var i = 0; i < originalList.length; i++){
var link = patientList[i].getElementsByTagName('a');
var link = link[0].text;
/** remove whitespaces for easy comparison **/
link = link.toLowerCase();
query = query.toLowerCase();
link = link.replace(/\s/g, "");
query = query.replace(/\s/g, "");
/** check every character in query **/
if (link.length > query.length && link.substring(0,query.length) == query){
found = true;
newList += '<li>' + patientList[i].innerHTML + '</li>';
}
}
if (found == true){
listContainer.innerHTML = newList;
newList = '';
}
else{
listContainer.innerHTML = "<li>No patient by that name</li>";
}
console.log(frozen);
}
</script>
const originalList = document.getElementById('patientList').getElementsByTagName('li').cloneNode(true);
Make originalList a copy of the element. Currently, you are setting originalList and patientList to be the same list of elements, so changing one will also change the other. Use element.cloneNode(true) to make a deep copy of a DOM element

How do you get a count of listitems of a certain content type without fetching all items

So we had a piece of code that set a few elements to display the count of all items in various lists.
Now a requirement has been added that only items of a certain content type can be counted. However, Including a caml query as seen below (The old code has been commented out) has made it far to slow for actual use. (obviously, its fetching thousands of items just to get a count).
Is there a way to count all items of a contenttype in a sharepoint list using javascript that doesn't request all items of every list?
function setCounter() {
context = new SP.ClientContext.get_current();
web = this.context.get_web();
this.lists = web.get_lists();
context.load(this.lists);
context.executeQueryAsync(
Function.createDelegate(this, function () {
var listsEnumerator = this.lists.getEnumerator();
while (listsEnumerator.moveNext()) {
var currentItem = listsEnumerator.get_current();
for (var i = 0; i < leng; i++) {
if (leng == 1) ele = listItemCount;
else ele = listItemCount[i];
if (decoded == currentItem.get_title()) {
ele.parentNode.setAttribute("class", "overview_discussions");
// var counter = currentItem.getItems();
// ele.innerText = currentItem.get_itemCount();
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("<Where><BeginsWith><FieldRef Name='ContentTypeName'/><Value Type='Text'>Discussion</Value></BeginsWith></Where>");
var counter = currentItem.getItems(camlQuery);
context.load(counter);
context.executeQueryAsync(function () { ele.innerText = counter.get_count(); }, executeOnFailure);
break;
}
}
}
}),
Function.createDelegate(this, executeOnFailure));
}
Nope, but what you can do is minimize the data pulling by setting viewfields. Now is like you are doing a select * when you only need select id
var caml = "<View><ViewFields><FieldRef Name='Id'/></ViewFields></View><Query>your query here</Query>";
After executing the query you just need to cal get_count() as you already do
If you are familiar with jQuery, I suggest you taking a look a this library, is very easy to use and helps you improve your work with object client model. http://spservices.codeplex.com/

Categories