Problem running multiple instances of a plugin - jquery-plugins

I developed a simple plugin to sent request to a JSON text file, retrieve a data containing image list and append the html in the element calling the plugin.
Now, the code is working fine while it is running on only one element, but when I am using it on more than one element, now the elements get loaded on the last element calling the plugin only.
Plugin Code:
$.fn.testPlugin = function(param) {
var options = {
url : "",
pause : 2000,
callback : 5000
};
this.each(function() {
elementId = $(this).attr("id");
options = $.extend(options,param);
if(options.url=="") { console.log("URL is not specified"); }
else {
$.post(
options.url,
function(data) {
$("#"+elementId).html("<ul></ul");
$.each(data.dashboard, function(k,v) {
html = '<li>';
html += '<a href="'+v.TargetUrl+'" target="'+v.Target+'">';
html += '<img src="' + v.ImageUrl + '" alt="' + v.Alt +'" title="' + v.OverlayText +'" />';
html += '</a><p>'+v.OverlayText+'</p></li>';
$("ul",$("#"+elementId)).append(html);
});
},
"json"
);
}
});
}
Plugin Initialization/Execution
$("#this").testPlugin({
url: 'test.txt'
});
$("#that").testPlugin({
url: 'text.txt'
});
HTML
<div id="this" style="border-style: solid;border-color: #09f;padding: 10px;">
This is a sample div.
</div>
<div id="that" style="border-style: solid;border-color: #09f;padding: 10px;">
Another div
</div>
UPDATE
I also found out that the problem is happening due to AJAX request. If I create static list and then append it on the div, this time this works with any number of instantiation. A demo of static call is here. Now, help me do the same by retrieving the list from an AJAX request.
UPDATE 2
Thanks to Groovek, Here is a demo of the actual problem. You can notice, that the elements of both requests are append to the last element.

You're assigning to elementID without declaring it. This means it'll be a global variable, which means it'll always be equal to the last thing assigned to it (in this case, #that). If you just keep a local reference to the element, the code will work. Here's a modified jsfiddle: http://jsfiddle.net/s9BDT/
Code inside the each 'loop':
var el = $(this);
el.html("<ul></ul>");
options = $.extend(options,param);
if(options.url=="") { console.log("URL is not specified"); }
else {
$.post(
//options.url,
"/echo/json/",
{json:'{"dashboard":[{"TargetUrl":"toto.html", "Alt" : "sample 1", "ImageUrl":"toto.png", "OverlayText":"toto"},{"TargetUrl":"titi.html", "Alt" : "sample 2", "ImageUrl":"titi.png", "OverlayText":"titi" }]}'},
function(data) {
//alert(data.dashboard);
html = '';
$.each(data.dashboard, function(k,v) {
html += '<li>';
html += '<a href="'+v.TargetUrl+'" target="'+v.Target+'">';
html += '<img src="' + v.ImageUrl + '" alt="' + v.Alt +'" title="' + v.OverlayText +'" />';
html += '</a><p>'+v.OverlayText+'</p></li>';
});
//alert(html);
$("ul",el).append(html);
},
"json"
);
}

Related

How to render ajax response to view

Here is my predicament: I need to render json response received from controller method. I do this by calling clicking on navbar item "List Articles" which activate method ajaxIndex(). Then tat method makes request to route which in turn call controller method also called ajaxIndex(). That method then gater all articles and sends it as a response. After that, that response i can't control, it just renders raw json ...
Navbar item:
<a class="nav-link" href="/articles" onclick="ajaxIndex(this)"> List Articles </a>
Route:
Route::get('/articles', "ArticlesController#ajaxIndex");
Method in ArticlesController
public function ajaxIndex(Request $request)
{
$var1 = $request->var1;
$var2 = $request->var2;
$elem = $request->elem;
$currUser = auth()->user();
$currUri = Route::getFacadeRoot()->current()->uri();
$articles = Article::orderBy("created_at","desc")->paginate(5);
$html = view('articles.List Articles')->with(compact("articles", "var1", "var2", "elem", "currUser", "currUri"))->render();
//return $request;
return response()->json(["success"=> true, "html" => $html], 200);
//return response()->json(["success"=> $articles,"var1"=> $var1, "var2"=> $var2, "elem"=> $elem, "currUser" => $currUser, "currUri" => $currUri], 200);
}
and here my ajax method
function ajaxIndex(me,formId){
let var1 = "gg";
let var2 = "bruh";
let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
let url = "/articles";
if(formId){
let form = $("#"+formId).serialize();
console.log(form);
}
$.ajax({
type: "GET",
url: url,
headers:{
"X-CSRF-TOKEN": token
},
data: {/*
var1: var1,
var2: var2,
elem: {
id: me.id ? me.id : null,
class: me.className ? me.className : null,
value: me.value ? me.value : null,
innerHTML: me.innerHTML ? me.innerHTML : null,
}
*/},
success: (data) => {
console.log(data);
$('#maine').html(JSON.parse(data.html));
},
error: (data) => {
console.log(data);
}
});
}
How to render acquired data to particular view?
Now just renders json response alongside html.
My question is how to render response itself and where goes response from controller method. I tried console logging it when route is hit, but there is nothing in console. What is actual approach or what i need to change to achieve this?
Addendum: "For List Articles you will send ajax request to rest api where it returns array of objects(articles)". I assumed i needed to make ajax request, after being sent to appropriate blade, i should now display sent data? Am i getting wrong something? ...
Edit1:
Now when i go to any page in my app, for example:
http://articleapp.test/articles?page=2
it shows json response:
Edit2:
I also modified my ajax method to correctly display current page for article listing. Problem start when try to go to next page.
Here is the code:
function ajaxIndex(me,formId){
let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
let url = "/articles";
if(formId){
let form = $("#"+formId).serialize();
console.log(form);
}
$.ajax({
type: "GET",
url: url,
headers:{
"X-CSRF-TOKEN": token
},
data: {},
success: (data) => {
console.log(data);
let html = "<div class='container'>";
let articleBody = "";
let pagination = "<ul class='pagination'><li class='page-item'><a class='page-link' href='#'>Previous</a></li>";
if(data.articles.data.length > 0){
for(let i=0;i<data.articles.current_page;i++){
let created_at = data.articles.data[i].created_at.replace(/-/g,"/").split(" ")[0];
html += "<div class='row' style='background-color: whitesmoke;'><div class='col-md-4 col-sm-4'><a href='/articles/"+data.articles.data[i].id+"'><img class='postCover postCoverIndex' src='/storage/images/"+data.articles.data[i].image+"'></a></div><div class='col-md-8 col-sm-8'><br>";
if(data.articles.data[i].body.length > 400){
articleBody = data.articles.data[i].body.substring(0, 400);
html += "<p>"+articleBody+"<a href='/articles/"+data.articles.data[i].id+"'>...Read more</a></p>";
}
else{
html += "<p>"+data.articles.data[i].body+"</p>";
}
html += "<small class='timestamp'>Written on "+created_at+" by "+data.articles.data[i].user.name+"</small></div></div><hr class='hrStyle'></hr>";
history.pushState(null, null, "/articles?page="+(i+1));
}
for(let i=0;i<data.articles.total;i++){
//console.log(data.articles.data[i].id);
pagination += "<li class='page-item'><a class='page-link' href='/articles?page="+(i+1)+"'>"+(i+1)+"</a></li>";
}
pagination += "<li class='page-item'><a class='page-link' href='#'>Next</a></li></ul>";
}
html+="<div class='d-flex' style='margin: 10px 0px;padding-top: 20px;'><div class='mx-auto' style='line-height: 10px;'>"+pagination+"</div></div></div>";
$('#maine').html(html);
//?page=2
},
error: (data) => {
console.log(data);
}
});
}
When i go to next page, it shows json response as i previously stated. Look in the image above. It won't render ...
In this case ajax response should contain only the real content you want to get with the assynchronous request (html tags inside body). Your #maine element should be a div or another structure capable of having html child tags.
Ps.: If you want to render the ajax response like another page by changing header tags and maybe even the http content type then the response should be load inside an iframe tag.
**Edit: ** In pratice, delete the previous content before body tag in the view returned by ajax. And #maine must be a to contain the ajax response.

Can I use fetch api in jquery-datatables?

I understand that you can use ajax to populate the datatable. But can you use fetch?
Because I have this normal table, filled dynamically using fetch api.
$(document).ready(function(){
fillTable();
})
//fetch api (AJAX) to fill table
fillTable = () => {
fetch('http://localhost:3000/home.json')
.then(response => response.json())
.then(data => {
let html = '';
for (i = 0; i < data.length; i++){
html += '<tr>'+
'<td class="tdUsername pv3 w-35 pr3 bb b--black-20">'+ data[i].username + '</td>'+
'<td class="tdPassword pv3 w-35 pr3 bb b--black-20">'+ data[i].password + '</td>'+
'<td class="pv3 w-30 pr3 bb b--black-20">'+
'<div class="btn-group" role="group" aria-label="Basic example">'+
'<a class="editButton f6 grow no-underline ba bw1 ph3 pv2 mb2 dib black pointer" data-toggle="modal">EDIT</a>'+
'<a class="deleteButton f6 grow no-underline ba bw1 ph3 pv2 mb2 dib black pointer" data-toggle="modal">DELETE</a>'+
'</div>'+
'</td>'+
'</tr>'
}
$('#tblBody').html(html);
})
.catch(err => console.log("ERROR!: ", err))
}
So I am wondering if I can use fetch-api instead of using this to fill the datatable.
//syntax copied from the website
$('#myTable').DataTable( {
ajax: '/api/myData'
} );
It is possible to use 'ajax' option as a function, see https://datatables.net/reference/option/ajax#function
As a function, making the Ajax call is left up to yourself allowing complete control of the Ajax request. Indeed, if desired, a method other than Ajax could be used to obtain the required data, such as Web storage or a Firebase database.
When the data has been obtained from the data source, the second parameter (callback here) should be called with a single parameter passed in - the data to use to draw the table.
Example:
$('#example').dataTable( {
"ajax": function (data, callback, settings) {
callback(
JSON.parse( localStorage.getItem('dataTablesData') )
);
}
});
I was looking for this answer myself as I am trying to stay away from jquery as much as possible, but was unable to find an answer anywhere. I ultimately figured it out on my own and the implementation is not very different than using DataTable's suggested jquery ajax call.
var myTable = $('#myTable').DataTable({
ajax: async function (data, callback, settings) {
let response = await fetch("/api/v1/some/end/point", {headers: {Authorization: 'Bearer ' + sessionStorage.getItem("token")}});
if (response.ok) {
let msg = await response.json();
sessionStorage.setItem('token', msg.token);
console.table(msg.data);
delete msg['token'];
callback(msg);
} else {
console.log(response);
}
},
...... followed by the usual DataTable options
if someone is looking for an answer.
Yes, you can use fetch to populate datatable, here is an example.
fetchEndPointData(dc)
.then(aggregatedData => {
$('#table1').dataTable().api().rows.add(aggregatedData);
}).catch(error => {
// When fetch ends with a bad HTTP status, e.g. 404
console.log(error.message);
});
invoked method
async function fetchEndPointData(dc) {
const response = await fetch('/someEndPoint=' + dc);
const movies = await response.json();
return movies;
}
Note : the fetchEndPointData is returning a promise.
reference : https://dmitripavlutin.com/javascript-fetch-async-await/

Bootstrap Typeahead with AJAX source (not working)

I'm trying to implement a search bar dropdown using bootstrap v3.0.0 with typeahead.js.
My search bar will take a student's firstname and lastname. I'm using a MYSQL database which consists of a table called practice with afirstname, alastname, aid as columns. The search bar should not only contain the firstname and lastname in the dropdown, but also the id associated with it in a second row. I've read all the examples on the typeahead.js page and I'm unable to do it with ajax call.
Below is the code of my index.php
JS
<script type="text/javascript">
$(document).ready(function() {
$('.cr.typeahead').typeahead({
source: header: '<h3>Select</h3>',
name: 'accounts',
source: function (query, process) {
return $.getJSON(
'localhost/resultly/source.php',
{ query: query },
function (data) {
return process(data);
});
});
});
</script>
HTML:
<body>
<div class="container">
<br/><br/>
<input type="text" name="query" class="form-control cr typeahead" id="firstname" />
<br/><br/>
</div>
</body>
Code for source.php : This should return the firstname and lastname from my database in the form of a json string or object?
<?php
$query = $_POST['query'];
try {
$conn = new PDO('mysql:host=localhost;dbname=practice','root','');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("SELECT * FROM actualtable WHERE afirstname LIKE '%($query)%'");
$stmt->execute();
}
catch (PDOException $e) {
echo 'ERROR:' . $e->getMessage();
}
foreach ($stmt as $row) {
$afirstname[] = $row['afirstname'];
$alastname[] = $row['alastname'];
}
echo json_encode($afirstname);
echo json_encode($alastname);
?>
result:
http://oi41.tinypic.com/50moi1.jpg
Nothing shows up. I've tried adding a prefetch:
prefetch: {
url: 'localhost/resultly/source.php',
filter: function(data) {
r1 = [];
for (var i = 0; i < data.length; i++) {
r1.push({
value: data[i].afirstname,
tokens: [data[i].afirstname, data[i]alastname],
afirstname: data[i].afirstname,
alastname: data[i].alastname,
template: '<p>{{afirstname}} - {{alastname}}</p>',
});
}
return r1;
}
}
Please do provide a solution or an example which I could refer.
Update:
The source.php should return a list of json encoded data. I debugged by looking at the output that the source.pho created. What I did wrong was whenever I was supposed to put a url I did localhost/source.php instead of just source.php.
Solution provided by Bass Jobsen works and now I have run into another problem.
I'm using
if(isset($_POST['query']))
{ $q_uery = $_POST['query'];
$query = ucfirst(strtolower($q_uery))};
to take the user's data and use it for searching logic
$stmt = $conn->prepare("SELECT * FROM actualtable WHERE afirstname LIKE '%($query)%'");
The updated source.php is http://pastebin.com/T9Q4m10g
I get an error on this line saying Notice: Undefined variable: stmt I guess the $query is not being initialized. How do I get this to work. Thanks.
Update 3
I used prefetch: instead of 'remote:' that did all the matching.
Your return is not correct:
echo json_encode($afirstname);
echo json_encode($alastname);
See for example Twitter TypeAhead.js not updating input
Try echo json_encode((object)$stmt);, see: typeahead.js search from beginng
Update
I tried echo json_encode((object)$stmt);still doesn't work.
Do you use any kind of debugging? What does? source.php return? Try to follow the steps from
typeahead.js search from beginng without the filter.
html:
<div class="demo">
<input class="typeahead" value="" type="text" spellcheck="off" autocomplete="off" placeholder="countries">
</div>
javascript:
$('.typeahead').typeahead({
remote: 'http://testdrive/source.php?q=%QUERY',
limit: 10
});
php (source.php):
<?php
$people = array();
$people[] = array("lastname"=>"Inaw",
"firstname"=>"Dsajhjkdsa");
$people[] = array("lastname"=>"Dsahjk",
"firstname"=>"YYYsgbm");
$people[] = array("lastname"=>"Dasjhdsjka",
"firstname"=>"JHJKGJ");
$datums = array();
foreach($people as $human)
{
$datums[]=(object)array('value'=>$human['firstname'],'tokens'=>array($human['firstname'],$human['lastname']));
}
echo json_encode((object)$datums);
This should work
update2
Thanks, it worked. How do I display 2 or more 'value'?
add some values to your datums in source.php:
foreach($people as $human)
{
$datums[]=(object)array
(
'value'=>$human['firstname'],
'tokens'=>array($human['firstname'],$human['lastname']),
'firstname'=>$human['firstname'],
'lastname'=>$human['lastname']
);
}
firstname and lastname now are field you csn use in your templates
Add a template and template engine to your javascript declaration:
$('.typeahead').typeahead({
remote: 'http://testdrive/source.php?q=%QUERY',
limit: 10,
template: [
'<p>{{firstname}} - {{lastname}}</p>'
].join(''),
engine: Hogan
});
The above make use of https://github.com/twitter/hogan.js. You will have to include the template engine by javascript, for example:
<script src="http://twitter.github.io/typeahead.js/js/hogan-2.0.0.js"></script>
It is working for me. please follow below step.
Please add below Js and give proper reference.
bootstrap3-typeahead
--- Ajax Call ----
$("#cityId").keyup(function () {
var al = $(this).val();
$('#cityId').typeahead({
source: function (valuequery, process) {
var states = [];
return $.ajax({
url: http://localhost:4000/GetcityList,
type: 'POST',
data: { valueType: "", valueFilter: valuequery },
dataType: 'JSON',
success: function (result) {
var resultList = result.map(function (item) {
states.push({
"name": item.Value,
"value": item.Key
});
});
return process(states);
}
});
},
});
});
---- Cs Code ---
public JsonResult SearchKeyValuesByValue(string valueType, string valueFilter)
{
List<KeyValueType> returnValue = SearchKeyValuesByValue(valueType, valueFilter);
return Json(returnValue);
}
Auto suggest of Bootstrap typehead will get accept only "name" and "value" so create reponse accordinly

update a div after deleting file, my ajax does not take my href id with mootools?

I am trying to archive this task, I got a script2.php where I list files from a directory and for every file there is a delete link, but when I press the delete link, my ajax mootools does not take the id of the href, it shows a message of undefined, all what I want to do is a similar effect like this but simple,
the question is how can I archieve that my mootools ajax take the id of href for pass to my deletefile.php?? I am updating the div when I delete but first that takes this event for deleting the file.
this is my code:
<script type="text/javascript">
window.addEvent('domready', function() {
$$('a.delete').addEvent('click', function() {
alert("Here I am");
//alert($$('a').id);
// var newDelete = new Request({
// method: 'GET',
// url: 'deletefile.php',
// data: 'identifier='+identifier,
// onRequest: function() {$('divShowmessage').innerHTML="Cargando...";},
// onSuccess: function(texto, xmlrespuesta) {alert($$('a').id);},
// onFailure: function(){alert('Error!');}
// }).send();
});
});
</script>
<?php
$ruta = "./uploadedfiles/";
$directory = dir($ruta);
$types = array('jpg', 'jpeg', 'txt', 'gif', 'png', 'doc', 'docx', 'pdf', 'xlsx', 'pptx');
$identifier = "";
while ($file = $directory->read()) {
$division = explode(".", $file);
$extension = end($division);
$identifier = $archivo;
if(in_array($extension, $types)){
<div id="delete">
echo $file . " <a id=\"". $identifier."\" href=\"#\">Delete</a><br>";
//echo $archivo . " <a id=\"". $identificador."\" href=deletefile.php?file=" . urlencode($file) .">Delete</a><br>";
//echo $file. "<a id=refresh href=# >Delete</a><br> ";
</div>
}
}
$directory->close();
?>
Using $$('a') inside of the addEvent method is not the right way of doing it.
What you're trying to do in the code above is get the id from an element collection (array).
What you want to od is do this.get('id')
Also, you want to stop the event, with event.stop()
See the example: http://jsfiddle.net/gSf2q/

CodeIgniter - Multiple file uploads using dynamic field generation

Im using a jquery script to add new file upload fields to my form dynamically, as a result, all my file fields look like so
<input class="file-input-area" name="mpfile[]" type="file" size="32" value="" />
So in other words, if i click the 'add more file upload' link 5 times, i get 5 file upload fields that look exactly as the one above.
Iam quite new to codeigniter and have done some research which tells me that if uploading multiple files, i should use the [] after the field name ... i hope this is right.
My problem now is figuring the process to upload the files, and store their names to a database table.
I have tried normal PHP uploading but it doesnt seem to be working, im not sure what to put in my view, controller and model.
If someone can give me an example of how they would go about it, it would help me so much.
Cheers,
Use jQuery uploadify. The files are uploaded asynchronously, see some demos here.
Here's an implementation:
jQuery('#images').uploadify({
'uploader' : '/uploadify/uploadify.swf',
'script' : '/uploadify/uploadify.php',
'cancelImg' : '/uploadify/cancel.png',
'folder' : '/data/images',
'auto' : true,
'fileExt' : '*.jpg;*.gif;*.png;*.jpeg;*.tif',
'fileDesc' : 'Web Image Files (.JPG, .GIF, .PNG, .JPEG, .TIF)',
'queueID' : 'images-queue',
'onCancel' : function(event,ID,fileObj,data) {
jQuery.ajax({
type: "POST",
url: "uploadify/delete_image.php",
data: "filepath=/data/images/" + jQuery("#"+ID).val(),
success: function(){
jQuery("#"+ID).remove();
queueSize = data.fileCount;
jQuery('#status-message').text('Photo uploaded!');
}
});
},
'onSelect' :function (event, ID) {
if (queueSize < maxQueueSize)
queueSize++;
else{
alert("Max number of files is " + maxQueueSize);
jQuery('#images').uploadifyCancel(ID);
return false;
}
},
'onSelectOnce' : function(event,data) {
jQuery('#status-message').text('File is currently uploaded...');
},
'onComplete': function (evt, queueID, fileObj, response, data) {
jQuery('#status-message').text('H φωτογραφία φορτώθηκε!');
jQuery("#field_photos").append("<input id="+ queueID +" type='hidden' name='pics[]' value='" + response + "' />"); //adds hidden form field
},
'onAllComplete' : function(event,data) {
},
'onClearQueue' : function (a, b) {
queueSize = 0;
},
'multi' : true,
'simUploadLimit' : 3,
'removeCompleted': false,
'sizeLimit' : 1048576,
'queueSizeLimit' : 1
});
With this line:
jQuery("#field_photos").append("<input id="+ queueID +" type='hidden' name='pics[]' value='" + response + "' />"); //adds hidden form field
we store the filenames in the hidden array field "pics". When your form is submitted, you read these names using $this->input->post('pics') and store them into your database.

Resources