Following the answer in this stackoverflow question, I am trying to run the following code. But the myfunction takes only one google visualization event. So Is the following code is valid? Or how to handle multiple statechange google visualization events in a single function?
var categoryPicker1, categoryPicker2;
function drawVisualization() {
// etc.
categoryPicker1 = // etc...
categoryPicker2 = // etc...
// Register to hear state changes.
google.visualization.events.addListener(categoryPicker1, 'statechange', myfunction);
google.visualization.events.addListener(categoryPicker2, 'statechange', myfunction);
// etc.
}
function myfunction() {
var whereClauses = [];
if (categorypicker1) {
whereClauses.push("something1 = '" + document.getElementsByClassName('goog-inline-block goog-menu-button-caption')[0].innerHTML + "'")
}
if (categorypicker2) {
whereClauses.push("something2 = '" + document.getElementsByClassName('goog-inline-block goog-menu-button-caption')[1].innerHTML + "'")
}
whereClause = whereClauses.join(" AND ");
// do something....
}
Not really clear from your question, but I assume you're building the SQL query to your database from the selected items in the CategoryPicker. Despite being an EXTREMELY bad/dangerous thing to do (building SQL client side, and sending it to a server), this should be possible by just grabbing the selectedItems from your CategoryPicker, and joining them with " AND ". Like:
values = categoryPicker1.getState().selectedValues;
values = values.concat(categoryPicker2.getState().selectedValues);
var args = values.map(function(_) { return "'" + _ + "'"; });
console.log(args.join(" AND "));
I wouldn't do this if I were you. I would pass the arguments up to the server, and remap them there (after appropriately filtering them, etc). Again this is very dangerous.
Related
Hi I am trying to get all documents library only created by the logged users. With the following code I get also libraries which was not created from a user. Thank you.
function GetAllLibraries() {
var listCollection = lists.getEnumerator();
while (listCollection.moveNext()) {
var listName = listCollection.get_current().get_title('Title');
document.getElementById('leftDiv').innerHTML += "<b>" + listName + "<b/>" + "<br />";
}
}
Since you are utilizing SharePoint JavaScript API (a.k.a JSOM) it is a bit tricky since SP.List object does not expose Author property to determine who created this object. But the good news that Author property could be extracted from SP.List.schemaXml property as demonstrated below
Here is a complete example how to retrieve lists created by current user
var ctx = SP.ClientContext.get_current();
var allLists = ctx.get_web().get_lists();
var currentUser = ctx.get_web().get_currentUser();
ctx.load(allLists,'Include(SchemaXml)');
ctx.load(currentUser);
ctx.executeQueryAsync(
function(){
var lists = allLists.get_data().filter(function(list){
var listProperties = schemaXml2Json(list.get_schemaXml());
var listAuthorId = parseInt(listProperties.Author);
return listAuthorId == currentUser.get_id();
});
console.log("The amount of lists created by current user: " + lists.length);
},
logError);
}
function schemaXml2Json(schemaXml)
{
var jsonObject = {};
var schemaXmlDoc = $.parseXML(schemaXml);
$(schemaXmlDoc).find('List').each(function() {
$.each(this.attributes, function(i, attr){
jsonObject[attr.name] = attr.value;
});
});
return jsonObject;
}
function logError(sender,args){
console.log(args.get_message());
}
If you want to know who created list or library, you need to get property SPList.Author. As i know, you can't get it by JSOM.
My advice for you is to develop your own http hanlder with logic on server-side and call it by ajax. For example, you pass arguments into handler like web url (_spPageContextInfo.webAbsoluteUrl), current user login or id (_spPageContextInfo.userId), and in handler iterate lists on web, compare current user and list creator. Finally, return needed lists info.
Or just develop web part and do the same: iterate lists and compare it with SPContext.Current.Web.CurrentUser
UPDATE:
Example of c# code. You can put it in your web part or event handler. In this code we iterate all lists on SPWeb and save lists title created by current user.
private void GetLists()
{
using (SPSite site = new SPSite("{site_url}"))
{
using (SPWeb web = site.OpenWeb())
{
SPListCollection listCol = web.Lists;
List<string> currentUserLists = new List<string>();
foreach(SPList list in listCol)
{
if (list.Author.ID == SPContext.Current.Web.CurrentUser.ID)
{
currentUserLists.Add(list.Title);
}
}
}
}
}
first off : I'm new to node, and a relative programming beginner.
I'm trying to create a small web app with Express, whose only goal is to fetch and reformat data from a website that doesn't have an open API.
To do so, I've decided to learn about scraping, and that brought me to Cheerio and Request.
I'm using reddit as an example, to learn on. The end goal in this example is to gather the name and href of the posts on the front page as well as the url leading to the comments, then to go on that page to scrape the number of comments.
What follows is the route that is called on a GET request to / (please excuse the variable names, and the comments/console.logs, I got frustrated) :
/*
* GET home page.
*/
exports.index = function(req, res){
var request = require('request')
, cheerio =require('cheerio')
, mainArr = []
, test = "test"
, uI
, commentURL;
function first() {
request("http://www.reddit.com", function(err, resp, body) {
if (!err && resp.statusCode == 200) {
var $ = cheerio.load(body);
$('.thing', '#siteTable').each(function(){
var url = $('a.title', this).attr('href')
, title = $('a.title', this).html()
, commentsLink = $('a.comments', this).attr('href')
, arr = [];
arr.push(title);
arr.push(url);
arr.push(commentsLink);
mainArr.push(arr);
});
second();
};
});
}
function second() {
for (i = mainArr.length - 1; i >= 0; i--) {
uI = mainArr[i].length - 1;
commentURL = mainArr[i][uI];
console.log(commentURL + ", " + uI + ", " + i);
var foo = commentURL;
request(foo, function(err, resp, body) {
console.log("what the shit");
// var $ = cheerio.load(body);
// console.log(mainArr.length + ", " + commentURL + ", " + i + ", " + uI);
// var test = $('span.title', 'div.content').html();
console.log(test + ", "+ foo + ", " + commentURL + ", " + i + ", " + uI);
// mainArr[1][2] = test;
});
};
if (i<=0) {
res.render('index', {title: test});
};
}
first();
};
The function first(); works as intended. It puts the title, the href and url to the comments in an array, then pushes that array in a master array containing those data points for all of the posts on the front page. It then calls the function second();
Said function's goal is to loop through the master array (mainArr[]), then select all of the urls leading to comments (mainArr[i][uI]) and launch a request() with that url as first parameter.
The loop works, but during the second call of request() inside the second() function, everything breaks down. The variable i gets set permanently at -1, and commentURL (the variable that is set to the URL of the comments of the current post), is defined permanently as the first url in arrMain[]. There are also weird behaviors with arrMain.length. Depending on where I place it, it tells me that arrMain is undefined.
I have a feeling that I'm missing something obvious (probably to do with asynchronicity), but for the life of me, I can't find it.
I would be really greatful for any suggestions!
You are correct about your guess, it's the infamous "Javascript loop Gotcha". See here, for example, for an explanation:
Javascript infamous Loop issue?
Besides that, it seems that only your debug prints are affected. The commented code regarding var test ought to work.
Finally, the kind of language is frowned upon in SO, you would do well to take 2 minutes and change your variable names in this post.
I'm trying to write a ORM in Node.js. I want to declare a class named Model which will be used to declare a data object, like:
Users = new Model(someModelRules);
newUser = new Users(userInfomation);
the data model User have a function named find(). Now, I want to make find() chained, like:
Users.find(" name = 'John' ")
.orderedBy("age").desc()
.limit(0,10)
or maybe just a simply find:
Users.find(" name = 'John' ")
to code this find function, I believe I must build the SQL first,and do the SQL query at the end of this find chain.
I don't know how to do this, all I can think of is to add a function like: doQuery(), so I will know it's time to do the SQL query when the doQuery() function was called, like:
Users.find(" name = 'John' ")
.orderedBy("age").desc()
.limit(0,10)
.doQuery();
I know this is a simply solution, but I don't want the extra doQuery() function. :(
So, how should I design this? It would so nice of you if you can show me some example code with comments.
Thx! (sorry for my poor English)
ps. I know the ORM2 has a find function I just want, but I wanna know how to code it and I can barely understand the code in ORM2 as there are no comments. (I'm not gonna use orm2.)
================================= SOLUTION ==============================
Inspired by #bfavaretto :
function User() {
this.find = function(id, condition) {
return new findChain(id, condition);
}
}
function findChain(id, condition) {
this._id = id
this._condition = condition
this.queryTimerSet = false;
this.scheduleQuery = function () {
var self = this;
if(!self.queryTimerSet) {
console.log('[TEST CASE: ' + self._id + '] Insert query into eventLoop');
setTimeout(function(){
console.log('[TEST CASE: ' + self._id + '] Start query: '+self._condition);
}, 0);
self.queryTimerSet = true;
} else {
console.log('[TEST CASE: ' + self._id + '] No need to insert another query');
}
}
this.orderedBy = function(column) {
console.log('[TEST CASE: ' + this._id + '] orderedBy was called');
this._condition = this._condition + ' ORDER BY ' + column
this.scheduleQuery();
return this;
}
this.desc = function() {
// simply add DESC to the end of sql
this._condition = this._condition + ' DESC'
}
this.scheduleQuery();
}
var user = new User();
user.find(1,'SELECT * FROM test').orderedBy('NAME1').desc();
user.find(2,'SELECT * FROM test').orderedBy('NAME2');
user.find(3,'SELECT * FROM test');
runnning this code, you will get the result:
[TEST CASE: 1] Insert query into eventLoop
[TEST CASE: 1] orderedBy was called
[TEST CASE: 1] No need to insert another query
[TEST CASE: 2] Insert query into eventLoop
[TEST CASE: 2] orderedBy was called
[TEST CASE: 2] No need to insert another query
[TEST CASE: 3] Insert query into eventLoop
[TEST CASE: 1] Start query: SELECT * FROM test ORDER BY NAME1 DESC
[TEST CASE: 2] Start query: SELECT * FROM test ORDER BY NAME2
[TEST CASE: 3] Start query: SELECT * FROM test
I believe there must be a better way to achieve this, but this is the best I can get for now.
Any comments?
It is possible to achieve that if you schedule the doQuery logic to run asynchronously (but as soon as possible). I am thinking on something like this:
function User() {
// Flag to control whether a timer was already setup
var queryTimerSet = false;
// This will schedule the query execution to the next tick of the
// event loop, if it wasn't already scheduled.
// This function is available to your model methods via closure.
function scheduleQuery() {
if(!queryTimerSet) {
setTimeout(function(){
// execute sql
// from the query callback, set queryTimerSet back to false
}, 0);
queryTimerSet = true;
}
}
this.find = function() {
// ... logic that builds the sql
scheduleQuery();
return this;
}
this.orderedBy = function() {
// ... logic that appends to the sql
scheduleQuery();
return this;
}
// etc.
}
One totally different approach is to have a single method for building the SQL, and passing the ORDER BY and LIMIT parameters in an options object. Then your call would look like this:
user.find({
what : " name = 'John' ",
orderedBy : "age DESC",
limit : "0,10"
});
This is more suited for SQL queries than what you're trying to do. What you have looks like noSQL stuff like MongoDB, where fetching the records and sorting are separate operations (I think).
You will always have to have a execute/doQuery function at the end of the chain.
This is because all the other functions before the doQuery help build the query that needs to be executed at the end.
I am adding a Google Analytics tracking event to nav menu links, with this code:
(function ($) {
"use strict";
$(function () {
$("body").on('click', '.menu-item a', function () {
var trackingCode = $(this).next(".ga-tracking");
if (trackingCode.length > 0) {
var t1 = trackingCode.data("tracking-1"),
t2 = trackingCode.data("tracking-2"),
t3 = trackingCode.data("tracking-3"),
t4 = trackingCode.data("tracking-4"),
params = "'" + t1 + "','" + t2 + "','" + t3 + "'";
_gaq.push([params]);
}
});
});
}(jQuery));
you can see it working here: http://paulwp.com/blog/
to trigger the code, click on the Blog link in the top black bar.
This is the error I get:
_gaq.push processing "'_trackEvent','Store_Outbound','Link_Click'" for args: "[]":
Called method "'_trackEvent','Store_Outbound','Link_Click'" threw exception.TypeError: Cannot call method 'apply' of undefined
whereas it should give something like this:
_gaq.push processing "_trackEvent" for args: "[Store_Outbound,Link_Click]":
guess it's the way I build the parameters with the variables that's causing the issue
You are passing the values wrong. This is effectively what you are doing:
_gaq.push(["a,b,c"]);
That is an array with a single element.
This is what it should look like:
_gaq.push(["a","b","c"]);
This is an array with multiple elements.
So basically you need to do
params = [t1,t2,t3];
_gaq.push(params);
or just put them directly in:
_gaq.push([t1,t2,t3]);
My jquery will not run my java script function on document ready.
cont += "<script>";
cont += "$(document).ready(function() {Puma.getReasonForBTI()});";
cont += "</script>";
JS function
Puma.getReasonForBTI = function() {
var reason = document.getElementById("reasonId").value;
var msql = "SELECT Pid FROM tPid WHERE Reason = 'reason'";
sql = "action=getReasonForBTI&sql=" + encodeURIComponent(msql);
objAjaxAd.main_flag = "getReasonForBTI";
objAjaxAd.SendQuery(sql);
}
Any help would be appreciated.
Why not just add the DocReady to your JS?
Puma.getReasonForBTI = function() {
var reason = document.getElementById("reasonId").value;
var msql = "SELECT Pid FROM tPid WHERE Reason = 'reason'";
sql = "action=getReasonForBTI&sql=" + encodeURIComponent(msql);
objAjaxAd.main_flag = "getReasonForBTI";
objAjaxAd.SendQuery(sql);
}
$(document).ready(function() {
Puma.getReasonForBTI()
});
EDIT:
Also, I would send reason by itself and Sanitize it server side, then put it into a query. Sending a SQL query over Javascript/AJAX is just asking for trouble.
Faux-Code:
sql("
SELECT Pid
FROM tPid
WHERE Reason = ?
", $ajax.reason)
DOUBLE EDIT
Also, putting reason in single quotes in a string does not evaluate the value of reason. Just figured I'd save you some future headache
var foo = "bar";
console.log("The value of foo is 'foo'");
=> "The value of foo is 'foo'"
console.log("The value of foo is " + foo);
=> "The value of foo is bar"
Try a chrome browser and the Development tools (F12).
Take a look at the errorconsole.
Fix the error
Change your Code, because Someone can use YOUR code to delete any data from the underlying database
update
var reason = document.getElementById("reasonId").value;
// reason is entered directly byy a user (or Mr. EvilHacker).
var msql = "SELECT Pid FROM tPid WHERE Reason = 'reason'";
// Here you create a SQL, which may sounds like this:
SELECT Pid FROM tPid WHERE Reason = ''; DROP table tPid;--'
if the evil hacker entered ';DROP table tPid;-- into the textbox. Look at owasp.org for further information