Widget to get data from external source with ajax call to include on tw - How to do it?

505 views
Skip to first unread message

Paulin Gjini

unread,
Aug 1, 2016, 5:53:47 AM8/1/16
to TiddlyWiki
Inserisci qui il codice...

Hello to all,
 I'm not good with js because I start developing a few months ago and I have a lot to learn but I'm trying to understand if it's possible to do this: 

  • Create a service (for example in php that, with a given url, respond with a descriprion of website (show test-2.php)
  • TW Widget that call this service and include the result in TW feed or if it's not possible create a new tiddler with the returned information
It's possible what i'm trying to do? 

test-2.php
<?php
  header
('Content-type: text/html');
  header
('Access-Control-Allow-Origin: *');
  $url
= $_GET['url'];

  $tags
= get_meta_tags($url);
  $description
= $tags["description"];
  echo
'<br /> url: ';
  print_r
($url);
  echo
'<br /> description: ';
  print_r
($description);
?>

Tw Widget $:/paulin/demo/getdata.js:

/*\
title: $:/paulin/demo/getdata.js
type: application/javascript
module-type: macro


<<getdata "url">>


\*/

(function(){


/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";


/*
 * Testing: get data with ajax
 */



exports
.name = "getdata";


exports
.params = [
 
{ name: "url" }
];


/*
 * Run the macro
 */

exports
.run = function(url) {
 
var url = url || "None";


       
function ajax(url) {
         
return new Promise(function(resolve, reject) {
           
var xhr = new XMLHttpRequest();
            xhr
.onload = function() {
              resolve
(this.responseText);
           
};
            xhr
.onerror = reject;
            xhr
.open('GET', url);
            xhr
.send();
         
});
       
}




var ret_val;
ajax
('./test-2.php?url='+url).then(function(result) {
          console
.log('**** > '+result);
   ret_val
= result;
         
return result;
       
}).catch(function() {
          console
.log('Error');
   ret_val
= "An error occurred";
         
return "An error occurred";
       
});
console
.log('----> '+ret_val);
return ret_val;        
};


})();

Thanks.
Paulin

Danielo Rodríguez

unread,
Aug 1, 2016, 9:46:15 AM8/1/16
to TiddlyWiki
Of course it's possible.

In fact several plugins do this, filesystem plugin, tiddlyweb, NoteSelf, etc. In fact your code seems to be correct for the task. What are you missing?

Message has been deleted

Paulin Gjini

unread,
Aug 1, 2016, 10:54:30 AM8/1/16
to TiddlyWiki
Hi Danielo,
   when I try to load  from my tw 


the response must be:

url: http://www.nytimes.com/

description
: The New York Times: Find breaking news, multimedia, reviews & opinion on Washington, business, sports, movies, travel, books, jobs, education, real estate, cars & more at nytimes.com

The response return after a few second (I show it in console) and in that time the return ret_val just finished running and turned null value because is event-driven and not procedural execution. For that I read on web for the Promise way and I try to implement but without result.


The service test-2.php is on a php web server on web and I'm calling it from my local tiddly wiki. The response of service take time and it doesn't return a value because is Asynchronous so it does not return and load as a Widget text result (showend as result of <<getdata "http://www.nytimes.com/">>). 

The idea is to have services on web servers that I can call with TW-Widget online to have information. Is like to call API from TW. It gives TW dynamic abilities that open different possibilities to call public API.  

Sorry for my bad english! 

Paulin.

Danielo Rodríguez

unread,
Aug 4, 2016, 11:52:30 AM8/4/16
to TiddlyWiki
I'm surprised that you got Promises working without any library. You are probably using a very modern browser.

Promises aside, you have to provide a callback to your function. Then, on the callback you perform the required operations.

/*
 * Run the macro
 */

exports
.run = function(url, callback) {

 
var url = url || "None";


[ ........ I REMOVED AJAX CODE .........]

ajax
('./test-2.php?url='+url).then(function(result) {
          console
.log('**** > '+result);
         
callback(null,
result); // it is a convention tu return the error in first place, and then the results. We don't get any error, so put null in place
       
}).catch(function(error) {
          console
.log('Error');
          callback(error)
       
});      
};

As you can see, I am not returning anything, I'm just calling the callback with the response. Then you should use it like this:

//this function will handle the results
function my_ResultHandler(err,result){
   
if(err){
     
return; //finalize execution, we got an error. You are already handling this on the promise, so no need for an extra handling here
   
}
   
//doo whatever you want with your result here, maybe creating a new tiddler?
   tw
.addTiddler({title:'ajaxResult', text:result})
}
 
//here you call your macro, widget or whatever
url
('my/url',my_ResultHandler);


Since you are using promises already you can return the promise on your url code (like you do on the ajax function) which is more cleaner:

//This time we don't need a callback because we are using promises

exports.run = function(url) {
 
var url = url || "None";

[.... I removed code here because it is the same ....]

return ajax('./test-2.php?url='+url).catch(
    function(err) {
          console
.log('Error!', err);
       
});

// you can handle errors, but it is not mandatory, you can just return the promise, so code above can become
// return ajax('./test-2.php?url='+url)

}

function my_ResultHandler(result){....} // we don't need the error here, because that is handled inside the .catch() statement.

//then calling it
url
('my/url').then(my_ResultHandler);


hope this helps


Paulin Gjini

unread,
Aug 8, 2016, 2:55:05 AM8/8/16
to TiddlyWiki
Thank you very much Danielo for your help.
You was very clear in your respone.

Have a nice day.
Paulin

PMario

unread,
Aug 8, 2016, 5:38:37 AM8/8/16
to TiddlyWiki
Hi Paulin,

Sorry for the late reply. .. TW has a basic callback based ajax utility built in: see: https://github.com/Jermolene/TiddlyWiki5/blob/master/core/modules/utils/dom/http.js
usage can be seen here: https://github.com/Jermolene/TiddlyWiki5/blob/master/plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js
Especially have a look how to use the "options-object"!

While not ideal, because this workflow is really old, difficult to read, write and understand, it should have the best browser compatibility. .. So it's backwards compatible :/

Some time ago I found a good explanation about promises: http://www.html5rocks.com/en/tutorials/es6/promises/
and a basic ajax implementation using promises: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Example_using_XMLHttpRequest
promise browser support: http://caniuse.com/#search=promises

which will be superseded in the future by window.fetch(), which imo hasn't enough browser support yet. see. http://caniuse.com/#search=fetch

have fun!
mario

Paulin Gjini

unread,
Aug 8, 2016, 11:18:43 AM8/8/16
to TiddlyWiki
Thenks a lot Mario.
I modify my macro and now it's ok. 
I will try again to implement it but the result it's fine for the moment.

In this example in a tiddler I call the macro with a url 

<<getDataFromUrl "Eureka" "https://en.wikipedia.org/wiki/Eureka_(word)">>

and after I will have a new tiddler loaded asynchronously with tiddlername = "Eureka" and the text of tiddler the returned data from service http://heckyesmarkdown.com/go/

Here is the code that I use:

/*\
title: $:/paulin/demo/getDataFromUrl.js
type: application/javascript
module-type: macro


<<getDataFromUrl "tiddlername" "url">>
Example to get data from wikipedia: <<getDataFromUrl "Eureka" "https://en.wikipedia.org/wiki/Eureka_(word)">>


\*/

(function(){


/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";



exports
.name = "getDataFromUrl";


exports
.params = [ {name: "tiddlername"},{name: "url"}];


/*
Run the macro
*/

exports
.run = function(tiddlername,url) {

 
var url = url || "None";

 
var tiddlername = tiddlername || "None";
 
 
//console.log("**** url > "+url);
 
//console.log("**** tiddler > "+tiddlername);
 
 
//thanks to http://heckyesmarkdown.com/ for the api to get markdown  
  $tw
.utils.httpRequest({url: "http://heckyesmarkdown.com/go/?u="+url, callback: function (error,data){
   
if (error){
    console
.log("ERROR:"+error);
   
}
    $tw
.wiki.addTiddler({title:tiddlername, text:data, type: "text/x-markdown"});
    console
.log(data);
 
}})
 
return "[["+tiddlername+"]]";
};


})();

Reply all
Reply to author
Forward
0 new messages