Jump to content

Search the Community

Showing results for tags 'ajax'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • Form Builder
  • ProFields
  • ProCache
  • ProMailer
  • Login Register Pro
  • ProDrafts
  • ListerPro
  • ProDevTools
  • Likes
  • Custom Development

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests

  1. Hi! Just started to dig into PW and since I have a small project starting I wonder that how does PW support dynamic forms out-of-the-box? Or perhaps through some module(s)? I'm creating a form(for visitors) that has options such as shape > size > color > availability/product which filter values for the last filter/select option (in this case availability). And is there any form field dependency implemented or is this just a matter of e.g. jquery events that trigger AJAX or visibility when field value is changed?
  2. There seems to be a problem with loading required javascript files for inputfields when a field is loaded via AJAX. For example, if I set the visibility of an Page reference field that uses asmSelect, the inputfield UI doesn't load (it's just a plain multi-select) and I'm seeing a JS error "$select.asmSelect is not a function". When ajax loads the fieldtype, it seems as though it's not loading jquery.asmselect.js Do these core inputfields need to be updated? How to write new inputfields so that the required js in included correctly when the field is loaded by AJAX? Has anyone found a solution to this? Thanks guys! -Brent edit: here's the announcement about these new AJAX options. It says that "The AJAX-driven features should now work with all core input fields (yes, even including files/images, repeaters (!), PageTable, asmSelect, and so on)." but it's not working for me in the Reno, or default theme. I'm working with the latest dev version of PW (2.6.17)
  3. Hi folks! For a website Iam working on I need to (pre)load a huge amount of images (100-500) from a folder in assets (wich I upload via FTP). To preload them I want to add them to the DOM inside a container, that I hide with css. This images will be use for a frame by frame animation (that animates with scrolling) so they should be loaded parallel and if the user clicks a cancel button, the loading should be canceled. (My website is using ajax to load pages with different animations, and the loading of the second animation waits till the loading of the first animation is loaded completly, wich I want to prevent). I want to use ajax to do this, so I can cancel the loading with xhr.abort(); Here is my code: var folder = '{$config->urls->assets}sequenzen/test/'; xhr = $.ajax({ url : folder, success: function (data) { $(data).find("a").attr("href", function (i, val) { if( val.match(/\.(jpe?g|png|gif)$/) ) { $(".preloader").append( "<img src='"+ folder + val +"'>" ); } }); } }); this will give me a 403 forbidden error. After some research I found out that I have to put a .htaccess in my assets folder. I also tried putting it in the sub folder "test", where the files are, but Iam still getting the error. Is there anything else Iam missing? Is there a configuration in PW i have to change to do that?
  4. Has anyone used pagination with ajax driven content? I'm using the MarkupPagerNav module to give me pagination, but my content is updated by an ajax post to refresh the body content of a table. The pagination links show a myproject/http404/?page=n for each link generated so they give a 404 page not found. I believe this is because the file containing my ajax code resides in the root of my project as a "web service" and does not have the access it needs, but I'm unsure really. If anyone can throw any light on this I would be very grateful. I include the code with my ajax below. <?php namespace ProcessWire; require_once ('./index.php'); // bootstrap ProcessWire if($config->ajax) { $pg = $pages->get("/single-use-carrier-bags/"); $selector = wire('input')->post('selector'); $mytableContent = ''; // hold the table markup // $retailer = $pg->children($selector); // for info. only $selector looks like this -> $retailer = $pg->children("sort=title, include=all, limit=10"); $pageinate = $retailer->renderPager(); echo $pageinate; foreach ($retailer as $r) { $mytableContent .= "<tr> <td><a href= '$r->url' target='_blank'>$r->title</a></td> <td>$r->category</td> <td>".numFormat($r->no_bags_issued)."</td> <td>".numFormat($r->gross_proceeds)."</td> <td>".numFormat($r->net_proceeds)."</td> <td>$r->other_use_net_proceeds</td> <td>".numFormat($r->amount_donated)."</td> <td>$r->good_causes_in_receipt</td> <td>".numFormat($r->no_paper_bags_issued)."</td> <td>".numFormat($r->no_bags_for_life)."</td> </tr>"; } echo $mytableContent; } ?>
  5. I have a table in my template that I would like to update using Ajax when a button is pressed. I am not sure how to go about this and hope somebody here could point me in the right direction. Here is my code for the table output. You can see I loop through the fields to output using a hard wired selector to list the retailer type. I have a button for Supermarkets that fires a js handler myFunc and I need to put the ajax there to call this page again with a param so I can then form the selector for supermarkets and update the table. When I get this working and understand how to do it in ajax I will code up a selector that is formed dependant on a bank of buttons and the table will update without the rest of the page - like magic! That's what ajax is for right?! Thanks for any help - Paul <button type="button" onclick="myFunc()" value="1" class="btn btn-primary">Supermarkets</button> <div class= "table-responsive"> <table class="table table-hover table-striped"> <thead> <tr> <th>Retailer</th> <th>No. bags issued</th> <th>Gross proceeds £</th> <th>Net proceeds £</th> <th>Other use of net proceeds</th> <th>Amount donated £</th> <th>Good causes in receipt of proceed</th> <th>No. of paper bags issued</th> <th>No. of bags for life</th> </tr> </thead> <tbody> <?php $pg = $pages->get("/single-use-carrier-bags/"); $retailer = $pg->find("category=DIY, sort=title, include=all"); foreach ($retailer as $r) { echo "<tr> <td><a href= '$r->url'>$r->title</a></td> <td>".numFormat($r->no_bags_issued)."</td> <td>".numFormat($r->gross_proceeds)."</td> <td>".numFormat($r->net_proceeds)."</td> <td>$r->other_use_net_proceeds</td> <td>".numFormat($r->amount_donated)."</td> <td>$r->good_causes_in_receipt</td> <td>".numFormat($r->no_paper_bags_issued)."</td> <td>".numFormat($r->no_bags_for_life)."</td> </tr>"; } ?> </tbody> </table> </div> </div> </div> <script type="text/javascript"> function myFunc() { } </script>
  6. hello, i have a _func.php file with this function. in the documentation i read that some api variables in functions are not available, so i use wire('pages'). function doSomething($u, $p) { $p = wire('pages')->get("id=$p"); $u = wire('pages')->get("id=$u"); $p->of(false); { ... populate repeater field stuff } $p->save(); } if i call this function in my home.php like doSomething(41,1093) (only for testing!) everything is fine, the function works, it add items to a repeater field. the german says "Wenn es dem Esel zu wohl ist, geht er aufs Eis", so i play around with ajax to fire up this function. $(document).ready(function() { $("#hit").click(function(){ $.ajax({ url: '<?= $config->urls->templates?>includes/_func.php/', type: 'post', data: {userID: "<?= $user->id ?>", pageID: "<?= $page->id ?>"}, success: function(output){ console.log(output); } }) }) }) i read something about variable scopes and i think i understand it a little bit. but i don't understand why doSomething(41,1093) works in home.php the ajax call runs into a Call to undefined function wire() ? also i tried if ($config->ajax) but no luck ... that's the relevant party of _func.php. function doSomething($u, $p) { $p = wire('pages')->get("id=$p"); $u = wire('pages')->get("id=$u"); $p->of(false); { ... populate repeater field stuff } $p->save(); } if(isset($_POST['userID']) && !empty($_POST['userID']) && isset($_POST['pageID']) && !empty($_POST['pageID'])) { $u = $_POST['userID']; $p = $_POST['pageID']; { ... } echo sendLike($u, $p); } where is my mistake? any ideas? thx
  7. Hello, I'm desperately trying to update my website to PW 3.0.62 and I'm facing issues to to module compatibility. I was stuck with Pages2Pdf which I managed to solve bu updating the module from Github, but now it's the Pages Web Service module... and this time, I don't know wht to do The Module is found there. But it is quite old and I can't find it in the modules catalogue... and my site is making quite a use of it (I can't think of a way to do otherwise, sorry...) After adding the FileCompiler=0 to the module pages, the error I'm stuck with is : Fatal error: Class 'WireData' not found in /home/celfred/PlanetAlert/site/modules/ServicePages/ServicePages.module on line 22 and I have no idea on what to do... I must admit I'm not a programmer but a middle-school teacher... (for your information, here's the site I'm talking about : http://planetalert.tuxfamily.org ) but I'm struggling hard to solve the different issues I have to face and I'm wlling to understand things. I have just spent many hours trying to make 2.8 work on my localhost (and it seems ok ) but I'd like to switch to 3.x to prepare the future If anyone had the will to spend a few minutes to try and help me, I would greatly appreciate. Thanks in advance ! If you need more information to understand my problem, feel free to ask.
  8. I want to implement tables with Dynatable populated via ajax. Here's what I could muster: if($config->ajax) { $results = $pages->find($sanitizer->selector()); foreach($results as $r) $array[] = [ $r->title, $r->modified ]; header("Content-type: application/json"); echo json_encode($array); exit; } $content .= <<<EOT <table id="my-ajax-table"></table> <script> $("#my-ajax-table").dynatable({ dataset: { ajax: true, ajaxUrl: '.', ajaxOnLoad: true, records: [] } }); </script> EOT; But that's really nothing. Pro tips?
  9. hi i want to post variables to a page via ajax to get result from my database depenting my post value so my ajax is: var clickval = clickelement.value; var dataval = "city=" + clickval; $.ajax({ type: 'POST', url: "*MY PAGE SMART URL*", // e.g. http://my_domain/my_page.... data: dataval, dataType: 'text', //or json, i try both complete: function(data, status){ alert(data.responseText); } }); and in php page: $getcity = $input->post->city; echo "value = ".$getcity; just to show my post value... and my alert is "value = ". $getcity is empty and $input has no value inside and it seems like post is never be done, but i have no error in my console... can anyone help me?
  10. Hi I'm using a lightly modified Version of ProcessSlider on my PW page (3.0.42). But I'm having a problem with the file upload. It's using Ajax File upload to upload images, which is working fine at first, but the images are only uploaded temporarily (creation date 01.01.1970) when an image is uploaded and saved. When pressing the "save"-Button, this does not change. I'm guessing it's due to changes from PW 2 to 3? This is the js that is calling the iframe upload, I think I don't know what to do to amke it save correctly. Anybody who can give me a hint? /** * ProcessWire iFrameImagePicker plugin * * Light verision of InputfieldCKEditor/plugins/pwimage/plugin.js * * @return callback(src, width, height) * */ function loadIframeImagePicker(page_id, callback) { var page_id = page_id;//$("#Inputfield_id").val(); var edit_page_id = page_id; var file = ''; var imgWidth = 0; var imgHeight = 0; var imgDescription = ''; var imgLink = ''; var hidpi = false; var modalUri = config.urls.admin + 'page/image/'; var queryString = '?id=' + page_id + '&edit_page_id=' + edit_page_id + '&modal=1'; if(file.length) queryString += "&file=" + file; if(imgWidth) queryString += "&width=" + imgWidth; if(imgHeight) queryString += "&height=" + imgHeight; queryString += '&hidpi=' + (hidpi ? '1' : '0'); if(imgDescription && imgDescription.length) { queryString += "&description=" + encodeURIComponent(imgDescription); } if(imgLink && imgLink.length) queryString += "&link=" + encodeURIComponent(imgLink); queryString += ("&winwidth=" + ($(window).width() - 30)); // create iframe dialog box var modalSettings = { title: "<i class='fa fa-fw fa-folder-open'></i> " + "Select Image", open: function() { } }; var $iframe = pwModalWindow(modalUri + queryString, modalSettings, 'large'); $iframe.load(function() { // when iframe loads, pull the contents into $i var $i = $iframe.contents(); if($i.find("#selected_image").size() > 0) { // if there is a #selected_image element on the page... var buttons = [ { html: "<i class='fa fa-camera'></i> " + "Insert This Image", click: function() { var $i = $iframe.contents(); var $img = $("#selected_image", $i); $iframe.dialog("disable"); $iframe.setTitle("<i class='fa fa-fw fa-spin fa-spinner'></i> " + "Saving Image"); $img.removeClass("resized"); var width = $img.attr('width'); if(!width) width = $img.width(); var height = $img.attr('height'); if(!height) height = $img.height(); var file = $img.attr('src'); var page_id = $("#page_id", $i).val(); var hidpi = $("#selected_image_hidpi", $i).is(":checked") ? 1 : 0; var rotate = parseInt($("#selected_image_rotate", $i).val()); file = file.substring(file.lastIndexOf('/')+1); var resizeURL = modalUri + 'resize?id=' + page_id + '&file=' + file + '&width=' + width + '&height=' + height + '&hidpi=' + hidpi; if(rotate) resizeURL += '&rotate=' + rotate; if($img.hasClass('flip_horizontal')) resizeURL += '&flip=h'; else if($img.hasClass('flip_vertical')) resizeURL += '&flip=v'; $.get(resizeURL, function(data) { var $div = $("<div></div>").html(data); var src = $div.find('#selected_image').attr('src'); callback(src, width, height); $iframe.dialog("close"); }); } }, { html: "<i class='fa fa-folder-open'></i> " + "Select Another Image", 'class': 'ui-priority-secondary', click: function() { var $i = $iframe.contents(); var page_id = $("#page_id", $i).val(); $iframe.attr('src', modalUri + '?id=' + page_id + '&modal=1'); $iframe.setButtons({}); } }, { html: "<i class='fa fa-times-circle'></i> " + "Cancel", 'class': 'ui-priority-secondary', click: function() { $iframe.dialog("close"); } } ]; $iframe.setButtons(buttons); $iframe.setTitle("<i class='fa fa-fw fa-picture-o'></i> " + $i.find('title').html()); } else { var buttons = []; $("button.pw-modal-button, button[type=submit]:visible", $i).each(function() { var $button = $(this); var button = { html: $button.html(), click: function() { $button.click(); } } buttons.push(button); if(!$button.hasClass('pw-modal-button-visible')) $button.hide(); }); var cancelButton = { html: "<i class='fa fa-times-circle'></i> " + "Cancel", 'class': "ui-priority-secondary", click: function() { $iframe.dialog("close"); } }; buttons.push(cancelButton); $iframe.setButtons(buttons); } }); }
  11. Hello, I try to realize some booking form via jQuery.post method. It works to send the data to the book.php file. Whats next ? How to handle the data right. this is the JS code jQuery.post("./book.php",{ xx_name: name, xx_email: email, xx_date: date, xx_time: time, xx_message:message, xx_contact: contact}, function(data) { jQuery(".book_online_form .returnmessage").append(data);//Append returned message to message paragraph if(jQuery(".book_online_form .returnmessage span.book_error").length){ jQuery(".book_online_form .returnmessage").slideDown(500).delay(2000).slideUp(500); }else{ jQuery(".book_online_form .returnmessage").append("<span class='book_success'>"+ success +"</span>") jQuery(".book_online_form .returnmessage").slideDown(500).delay(4000).slideUp(500); setTimeout(function(){ $.magnificPopup.close() }, 5500); } if(data==""){ jQuery(".book_online_form")[0].reset();//To reset form fields on success } }); It works for me i get the data but what now ? how to handlte this right ? this is the post.php <?php include("./index.php"); // include header markup $sent = false; $error = ''; $emailTo = 'my@email.here'; // or pull from PW page field // sanitize form values or create empty $form = array( 'fullname' => $sanitizer->text($input->post->name), 'email' => $sanitizer->email($input->post->email), 'comments' => $sanitizer->textarea($input->post->message), ); print "CONTENT_TYPE: " . $_SERVER['CONTENT_TYPE'] . "<BR />"; $data = file_get_contents('php://input'); // Dont really know what happens but it works print "DATA: <pre>"; var_dump($data); var_dump($_POST); var_dump($form); print "</pre>"; if($input->post->submit) { $name = $_REQUEST['xx_name']; echo "Welcome 1". $name; // DONT WORK }else{ echo "Something is wrong on the submit "; } if( $_REQUEST["xx_name"] ) { $name = $_REQUEST['xx_name']; echo "Welcome 2". $name; // WORK } I have attached the output. how to act with the pw $input->post->submit and the form array for example ??
  12. I'm in the process of rebuilding a WordPress site over into ProcessWire (Yay!) I'm using Ajax to call a page (ajaxAgenda) from the homepage which includes a PHP file (partialAgenda) which makes the call. This is what I got in the included partial. Notice that the URL has a / at the end to prevent redirection. var page_number = 1; var get_agenda = function(){ $.ajax({ type : "GET", data : {pnum: page_number}, dataType : "html", url : "/components/ajaxAgenda/", beforeSend : function(){ $('#ajax-loader2').show(); }, success : function(data){ $('#ajax-loader2').hide(); $('#agenda').html(data); } }); } And in the Ajax called file I have the following echo $page->url.'<br>'; echo $input->get->pnum.'<br>'; echo $_GET['pnum'].'<br>'; which only outputs "/components/ajaxagenda/". pnum is empty and get is also also empty It seems like the variables are simply being stripped from my Ajax call. Or am I missing something really obvious?
  13. Hi everyone I've started to build a newsfeed for a customer, but I'm stuck... I have a news-repeater field including date, title, text and images. I have the link (showing date and title) to each news on the left (with foreach) and the details on the right (showing date, title, text and images also with foreach). I would love to only show the current news on the right. The latest news should be visible on the right. When I click on the link on the left side, it should change the news content on the right side. Does anyone have a simple solution for this? Here's how it looks like at the moment: http://rolspace.net/hd/energiegossau/uber-uns/news/ Thank you! Roli
  14. After this tutorial you'll have learned how to: Build a Process module Make an AJAX request to backend Serve JSON as response Let's say you want to display the latest orders in a dashboard that you can access from admin panel. And you want it to refresh its content with a button click. Most straightforward and proper way (that I know of) is to create a Process module, as they're built for this purpose. First, create a directory under /site/modules/, call it ProcessDashboard, and create a file named ProcessDashboard.module under that directory. Following is about the least amount of code you need to create a Process module. <?php namespace ProcessWire; class ProcessDashboard extends Process { public static function getModuleInfo() { return [ 'title' => 'Orders Dashboard', 'summary' => 'Shows latest orders', 'version' => '0.0.1', 'author' => 'abdus', 'autoload' => true, // to automatically create process page 'page' => [ 'name' => 'order-dashboard', 'title' => 'Orders', 'template' => 'admin' ] ]; } public function ___execute() { return 'hello'; } } Once you refresh module cache from Modules > Refresh, you'll see your module. Install it. It will create an admin page under admin (/processwire/) and will show up as a new item in top menu, and when you click on it, it will show the markup we've built in execute() function. All right, now let's make it do something useful. Let's add create a data list to display latest orders. We'll change execute() function to render a data table. public function ___execute() { /* @var $table MarkupAdminDataTable */ $table = $this->modules->MarkupAdminDataTable; $table->setID($this->className . 'Table'); // "#ProcessDashboardTable" $table->headerRow([ 'Product', 'Date', 'Total' ]); // fill the table foreach ($this->getLatest(10) as $order) { $table->row([ $order['title'], $order['date'], $order['total'] ]); } // to refresh items $refreshButton = $this->modules->InputfieldSubmit; $refreshButton->name = 'refresh'; $refreshButton->id = $this->className . 'Refresh'; // "#ProcessDashboardRefresh" $refreshButton->value = 'Refresh'; // label of the button return $table->render() . $refreshButton->render(); } where getLatest() function finds and returns the latest orders (with only title, date and total fields) protected function getLatest($limit = 5, $start = 0) { // find last $limit orders, starting from $start $orders = $this->pages->find("template=order, sort=-created, limit=$limit, start=$start"); // Only return what's necessary return $orders->explode(function ($order) { return [ 'title' => $order->title, 'date' => date('Y-m-d h:i:s', $order->created), 'total' => $order->total ]; }); } When you refresh the page, you should see a table like this Now we'll make that Refresh button work. When the button is clicked, it will make an AJAX request to ./latest endpoint, which will return a JSON of latest orders. We need some JS to make AJAX request and render new values. Create a JS file ./assets/dashboard.js inside the module directory. window.addEventListener('DOMContentLoaded', function () { let refresh = document.querySelector('#ProcessDashboardRefresh'); let table = document.querySelector('#ProcessDashboardTable'); refresh.addEventListener('click', function (e) { // https://developer.mozilla.org/en/docs/Web/API/Event/preventDefault e.preventDefault(); // Send a GET request to ./latest // http://api.jquery.com/jquery.getjson/ $.getJSON('./latest', { limit: 10 }, function (data) { // check if data is how we want it // if (data.length) {} etc // it's good to go, update the table updateTable(data); }); }); function renderRow(row) { return `<tr> <td>${row.title}</td> <td>${row.date}</td> <td>${row.total}</td> </tr>`; } function updateTable(rows) { table.tBodies[0].innerHTML = rows.map(renderRow).join(''); } }); And we'll add this to list of JS that runs on backend inside init() function public function init() { $scriptUrl = $this->urls->$this . 'assets/dashboard.js'; $this->config->scripts->add($scriptUrl); } Requests to ./latest will be handled by ___executeLatest() function inside the module, just creating the function is enough, PW will do the routing. Here you should notice how we're getting query parameters that are sent with the request. // handles ./latest endpoint public function ___executeLatest() { // get limit from request, if not provided, default to 10 $limit = $this->sanitizer->int($this->input->get->limit) ?? 10; return json_encode($this->getRandom($limit)); } Here getRandom() returns random orders to make it look like there's new orders coming in. protected function getRandom($limit = 5) { $orders = $this->pages->find("template=order, sort=random, limit=$limit"); return $orders->explode(function ($order) { return [ 'title' => $order->title, 'date' => date('Y-m-d h:i:s', $order->created), 'total' => $order->total ]; }); } And we're done. When refresh button is clicked, the table is refreshed with new data. Here it is in action: 2017-04-29_19-01-40.mp4 (227KB MP4, 0m4sec) Here's the source code: https://gist.github.com/abdusco/2bb649cd2fc181734a132b0e660f64a2 [Enhancement] Converting page titles to edit links If we checkout the source of MarkupAdminDataTable module, we can see we actually have several options on how columns are built. /** * Add a row to the table * * @param array $a Array of columns that will each be a `<td>`, where each element may be one of the following: * - `string`: converts to `<td>string</td>` * - `array('label' => 'url')`: converts to `<td><a href='url'>label</a></td>` * - `array('label', 'class')`: converts to `<td class='class'>label</td>` * @param array $options Optionally specify any one of the following: * - separator (bool): specify true to show a stronger visual separator above the column * - class (string): specify one or more class names to apply to the `<tr>` * - attrs (array): array of attr => value for attributes to add to the `<tr>` * @return $this * */ public function row(array $a, array $options = array()) {} This means, we can convert a column to link or add CSS classes to it. // (ProcessDashboard.module, inside ___execute() method) // fill the table foreach ($this->getLatest(10) as $order) { $table->row([ $order['title'] => $order['editUrl'], // associative -> becomes link $order['date'], // simple -> becomes text [$order['total'], 'some-class'] // array -> class is added ]); } Now, we need to get page edit urls. By changing getLatest() and getRandom() methods to return edit links in addition to previous fields protected function getLatest($limit = 5, $start = 0) { // find last $limit orders, starting from $offset $orders = $this->pages->find("template=order, sort=-created, limit=$limit, start=$start"); return $orders->explode(function ($order) { return [ 'title' => $order->title, 'date' => date('Y-m-d h:i:s', $order->created), 'total' => $order->total, 'editUrl' => $order->editUrl ]; }); } protected function getRandom($limit = 5) { $orders = $this->pages->find("template=order, sort=random, limit=$limit"); return $orders->explode(function ($order) { return [ 'title' => $order->title, 'date' => date('Y-m-d h:i:s', $order->created), 'total' => $order->total, 'editUrl' => $order->editUrl ]; }); } and tweaking JS file to render first column as links function renderRow(row) { return `<tr> <td><a href="${row.editUrl}">${row.title}</a></td> <td>${row.date}</td> <td>${row.total}</td> </tr>`; } we get a much more practical dashboard.
  15. I am implementing the ability to handle form submission using AJAX. The problem I have is that even though, as far as I can tell, I convert the AJAX-submitted JSON input into the equivalent of $input->post. When I call $form->processInput() it always throws that it appears to be forged. if ($config->ajax && $_SERVER['REQUEST_METHOD'] === 'POST') { // get the file body and decode the JSON. try { $body = file_get_contents('php://input'); $json = wireDecodeJSON($body); //wire('log')->save('info', 'ajax-json:' . print_r($json, true)); wire('log')->save('info', 'json-data:' . print_r($json['data'], true) . ' sid: ' . session_id()); $fakeinput = new WireInputData($json['data']); $form = deleteRequest('xyzzy'); $form->processInput($fakeinput); } catch (Exception $e) { http_response_code(404); echo json_encode(array('reason' => $e->getMessage())); } return; The log shows that the TOKEN and the TOKEN value are the same as when a normal form is submitted (I have both on the page for testing and can submit via normal POST as well as via AJAX). The session_id() value is the same. What am I missing? Log entries ("dumb" is the normal submit button name, "fake-text" is an empty text field, "submit" is the AJAX submit button name.) (using form-post): post Array ( [dumb] => dumb-button [TOKEN1649939534X1479234443] => f4VLZ17RlXfp9KVCQr/GIhoZ3krbuWK5 ) (using ajax-post): json-data: Array ( [fake-text] => [submit] => DELETE ENDUSERS [TOKEN1649939534X1479234443] => f4VLZ17RlXfp9KVCQr/GIhoZ3krbuWK5 )
  16. Hi folks, On the website I am working on I do have a form which needs to be filled in (duh) and when the user clicks on download, the data is send with ajax and processed in the same file by using the ProcessWire API with $config->ajax; The data which is provided by the user will be checked with data in my database. If the data is correct I want to push a file download. But this is not working at the moment. It seems like the content of the (.exe) file is pasted in the console instead of pushing the file. My code looks like this: if ($config->ajax){ $serial = $input->post('serial'); $DB = DB(); $query = $DB->prepare("/*My query here*/"); $query->bindParam("comparision", $serial, PDO::PARAM_STR); $query->execute(); $reply = ''; $SN_rows = $query->rowCount(); if (!$SN_rows > 0) { $reply = 'error'; } else { $reply = 'success'; $installer = $page->attachments->eq(1); $filename = "Filename"; $filepath = $installer->filename; $options = array( 'forceDownload' => true, 'exit' => true, 'downloadFilename' => $filename ); wireSendFile($filepath, $options); } echo $reply; exit(); } What am I doing wrong here or is it a bug? Is there another way to do this with the processwire API? Thanks in advance, ~Harmen
  17. I have been wanting to set up a quick "dashboard" for a recent project, and was considering using ajax to get a "real time" update/refresh on the page (some of my output depends on the datetime field). I know how to get the desired output using php with some if statements comparing todays date to the date stored in the field, however, I am a bit at a lose of how to interact with the ProcessWire API using ajax to get the desired effect. I found the following and know that I need to start off with: <?php if($config->ajax) { // page was requested from ajax } Unfortunately, as I mentioned earlier, how would one actual find pages using a template and get the field contents from them using AJAX? I apologize if this seems bit broad, but I am stil getting a grasp of using AJAX to deliver content to get a real time update on a page without refresh.
  18. I'm trying to call an ajax function for an inputfield using Soma's method below by intercepting the call in the module init function but for some reason $this->input is always NULL. public function init() { parent::init(); $dir = dirname(__FILE__); require_once("$dir/Location.php"); require_once("$dir/LocationArray.php"); $this->wire('config')->js('InputfieldLocations', array( 'url' => "/admin/locationmodule/ajax" )); if ($this->config->ajax && $this->input->ajaxfunction == 'getcities') { header('Content-Type: application/json'); echo $this->get_cities(); exit; } }
  19. Hi, I am building a site containing around 50000 products which will be updated on a regular basis. We are far from putting this site into production. I am actually devising the future functionalities. The actual update script uses an AJAX process so to avoid timeout. However, the update process will have to be fired automatically, something with either curl or phantom.js. What I have coded at the moment isn't probably not the best solution, albeit it works pretty well. There is a PW template called from an address : http://example.com/start-ajax which starts on load a simple jQuery Ajax process. The 50000 products are listed in a CSV file that is previoulsy broken down into small pieces (200 lines per file). The process is smooth and takes 40 minutes to read the data and update/or create Processwire pages accordingly. I would like to know your advices, your experience in that matter. What would you do to create an automated batch file?
  20. Hey, I've been trying to implement some progressive enhancements to take advantage of modern browsers, modern JS and CSS capabilities etc. One thing I've got stuck is to CSRF protection using $session->CSRF. I'm echoing hidden token using <?= session()->CSRF->renderInput('contact') ?> inside the form, and I can validate the token with plain POST request (without AJAX) just fine using session()->CSRF->hasValidToken('contact'). For AJAX, I'm setting headers x-<tokenname>:<tokenvalue>. It shows up in both Chrome DevTools correctly, and on backend lke HTTP_X_<TOKENNAME> => <TOKEN_VALUE> as expected, so there's no miscommunication. But, when I try to validate it, it fails no matter what. After some debugging I realized at each request, a new token is created, which invalidates the one I'm sending. Here are the relevant parts from the core. Inside /wire/core/SessionCSRF.php, where validation occurs <?php public function hasValidToken($id = '') { $tokenName = $this->getTokenName($id); $tokenValue = $this->getTokenValue($id); // ... if($this->config->ajax && isset($_SERVER["HTTP_X_$tokenName"]) && $_SERVER["HTTP_X_$tokenName"] === $tokenValue) return true; if($this->input->post($tokenName) === $tokenValue) return true; // if this point is reached, token was invalid return false; } it gets token name from here where it checks inside $_SESSION variable <?php public function getTokenName($id = '') { $tokenName = $this->session->get($this, "name$id"); // Why can't it find token inside $_SESSION global? if(!$tokenName) { $tokenName = 'TOKEN' . mt_rand() . "X" . time(); // token name always ends with timestamp $this->session->set($this, "name$id", $tokenName); } return $tokenName; } I dont understand why it cannot find correct token and regenerates? Does session not last until browser closes? I can save other data to $session, and get it just fine, am I missing something?
  21. Hi, I am using pagination with ajax. When i click on any page number url not changing because of ajax call So when i click on page 3 and then click on page 7 i hit the back button it returns to page 1 because url never changing Here is my site: www.sediremlak.com For real estate sites if visitor find a property on page 4 and click on that property page. After click on back button site jumps to first page or home page not page 4 How can i fix this problem?
  22. Trying to do some ajax calls to an api named somedomain.com/xapi/index.php using intercoolerjs in my home page. I'm trying to make calls like this in intercoolerjs. somedomain.com/xapi/controller/method. Looked through a bunch of the posts but nothing seems to match what I am trying to do. Is there a change I can make to the htaccess file to get this to work? Anyone have a suggestion on this or is there a better way to handle the api?
  23. I had situations come up that just seemed like AJAX was the right way to handle interactions with the ProcessWire server - pages with an element like a button or link that should cause an action to occur but shouldn't require a form or actually following a link - it should just take the action and only update the toggle (a checkbox in this case) when the interaction is completed. Another use case is with a large page on which there are multiple possible interactions. When the page is heavy enough that redrawing results in a less than optimal user experience then it's nice to be able to submit a form without having to redraw the page in order to update the relevant parts. So with that preamble, here's what I put together. I was going to try to clean it up a bit but that has prevented me from posting this so I figured it's better to post it and clean it up if there is any interest. You'll see references to the namespace whale - the name of our project - that would ultimately be removed. There are two major components - the PHP side and the client-side. On the PHP side there are two functional areas: 1. "wrapping" an entity to be inserted into the HTML on a page Wrapping (the function 'makeContainer()' puts a predefined wrapper around one of three types of objects: FormBuilderForm, InputfieldForm, or Template). The wrapper provides context and attaches classes that allows the client JavaScript code to find the wrapper and figure out what to do with it. // // define a function that makes a "form" of a single button. // function makeButton ($label) { // get the form $form = wire('modules')->get("InputfieldForm"); $form->attr('action', './'); $form->attr('method', 'post'); $submit = wire('modules')->get("InputfieldSubmit"); $submit->attr('id+name', 'submit'); $submit->attr('value', $label); $form->add($submit); return $form; } // wrapper function to set label on submit button function requestUserDeleteList() { return makeButton('Do it!'); } // // makeContainer wraps the rendered InputfieldForm in HTML so the client JavaScript can recognize it and handle // AJAX interactions with the server. // It returns the InputfieldForm object and the HTML to be inserted into the page. Note that makeContainer // is in a different namespace so it requires the function name must be qualified with the \ProcessWire prefix. // list ($form, $deleteUsersHTML) = ajax\Request::makeContainer('do-something', '\ProcessWire\requestUserDeleteList'); 2. helping with the processing of an AJAX request that is submitted to the page. Helping with the AJAX request - the code is invoked on page load and determines where there is a valid AJAX request from something it wrapped. It also allows messages to be returned, classes to be added or removed from specific elements, redirects to be executed, or even wholesale replacement of DOM elements (with plenty of caveats). It will even update a submit key so it is possible for the client to execute a single transaction multiple times. // get a new request object for the AJAX transaction $request = new ajax\Request(); // if it isn't formatted correctly handle the error if (!$request->isValidCall()) { return $request->echoError(); } // get the data and function-specific contents (Whale Ajax Context) $data = $request->data(); $wac = wireDecodeJSON($data['wac']); // if ($request->id('wants-newsletter')) { if (!ajax\Request::hasCorrectProperties($data, ['wac', 'value'])) { return $request->echoError(__('invalid call')); } // implement function here } else if ($request->id('another-function')) { // implement function here } // it didn't match any of the AJAX IDs implemented return $request->echoError('not implemented'); The client code requires jQuery and is packaged as three separate functions because both the form and template processing share a common core set of functions. My original intent was to only load the form or non-form code as needed but they're small enough that it really doesn't matter. See attachments for the Request class and the client code. There are many helper functions. Here is a kind of an unfocused extract that illustrates using the code with more context (from an internal sandbox page): <?php namespace ProcessWire; using whale\ajax; // include server-side code for making forms and processing them require_once './utility/ajaxform.inc'; // custom version of ProcessWire/wire/core/WireFileTools.php render() that returns the // template object, not the rendered HTML require_once './utility/get-file-template.inc'; // START AJAX submitted form processing - decodes the request and stores results in $aaform. $aaform = new ajax\Request(); // // this page handles multiple ajax calls so I check to see if it is valid once and then check IDs. // It's also possible to use $aaform->isValidCall('get-user-delete-list') to check specifically // for a specific AJAX ID. The ID is the name provided to Request::makeContainer() when the object // is wrapped. It's also possible to make calls to $aaform->id('get-user-delete-list') to check // for a specific ID. // // to create the forms/input elements that are submitted via AJAX start with: // Request::makeContainer('unique-name-on-page', object) // unique-name-on-page will become the ID of the element that wraps your object. // object - one of ProcessWire\InputfieldForm, \FormBuilderForm, ProcessWire\Template. // if ($aaform->isValidCall()) { if ($aaform->id() === 'get-user-delete-list') { $form = requestUserDeleteList(); // process using the form. the Request object will check to make sure it's the right type. if (!$aaform->process($form)) { return $aaform->echoError(); } // build new form with usernames for selections to delete. the function getUsersToDelete() // returns a user count and a function that will make the form that includes the users in // a list of checkboxes. list($usercount, $formmaker) = getUsersToDelete(); // this returns a replacement to part of the existing DOM. There are limitations but it // handles adding a form or replacing an existing form. if ($usercount === 0) { $replacement = '<div id="ajax-place">No users to delete</div>'; } else { // we pass the $formmaker function to makeContainer(). It returns the form and the // rendered wrapper and form. list($xform, $xhtml) = ajax\Request::makeContainer('do-delete', $formmaker); $replacement = '<div id="ajax-place">' . $xhtml . '</div>'; } // this makes sure the return is formatted so the client can handle it correctly. in // this case a replacement in the DOM is being returned. The first argument is the // selector, the second is the HTML to replace the selected element with. return $aaform->echoReplacement('#ajax-place', $replacement); } else if ($aaform->id() === 'do-delete') { list($usercount, $formmaker) = getUsersToDelete(); // process using the form returned by $formmaker. this will check to make sure it's // the right type of form. This abstracts FormBuilder forms and InputfieldForms. if (!$aaform->process($formmaker())) { return $aaform->echoError(); } // a bunch of logic where the checked users are deleted $deleted = []; $failed = []; $data = $aaform->data(); foreach($data as $name => $value) { if ($name === $value) { $user = wire('users')->get("name=$name"); $email = $user->email; // delete the user and try to get it again to see if the delete worked wire('users')->delete($user); $u = wire('users')->get("name=$name"); if (!count($u)) { $deleted[] = $email . " ($name)"; } else { $failed[] = $email . " ($name)"; } } } $deleted_users = $failed_deletions = ''; if ($deleted) { $deleted_users = 'deleted:<br/>' . join($deleted, '<br/>') . '<br/>'; } if ($failed) { $failed_deletions = 'failed to delete:<br/>' . join($failed, '<br/>') . '<br/>'; } $replacement = '<div id="ajax-place">' . $deleted_users . $failed_deletions . '</div>'; return $aaform->echoReplacement('#ajax-place', $replacement); } else if ($aaform->id() === 'contact') { // here a FormBuilderForm is being loaded if (!$aaform->process($forms->load('contact'))) { return $aaform->echoError(); } // this sends a notice back. the client will place it in a predefined notice area. // Request::makeContainer() will create an area for notices (or you can supply one). // It is also possible to return errors; notices and errors get different classes. $msg = ajax\Request::makeNotice('bruce says hi'); return $aaform->echoSuccess($msg); } else { // it was a valid form but it doesn't match any ID that this page knows about. return $aaform->echoError('what is this?'); } } // normal processing to render the initial page follows as it was not a valid AJAX post // that is handled by Request(). That's a lot of code, so I won't post anymore. If people have interest I'm happy to explain or provide other bits of code, like the extracted get-file-template.inc function. Wrapping a template is similar to wrapping a form except that only certain HTML elements are tracked and each are sent to the server when they are clicked on (technically it varies). It handles radio buttons, checkboxes, links, and buttons (radios and checkboxes on "change" and links and buttons on "click"). So when a checkbox is checked an AJAX call will be made so it can be acted upon by the server. @microcipcip, @ryan, @valan (sorry to any if this isn't interesting to you - I did a quick scan of what looked like semi-related AJAX posts). ajaxform.inc ajaxclient.js
  24. Trying to deploy a PW site to a client's hosting provider. Everything works as expected in development, but on the production host, certain AJAX requests fail. Here's what I'm seeing: 1) I have form on every page which is submitted via AJAX POST to the current page. No matter which page you POST to, it always returns a PW 404 page. 2) AJAX image uploads on the back end return a 200 or 302 for the original request, then spawn a GET request for the homepage. In trying to troubleshoot this, I have found that the host has both suhosin and mod_security installed. They've provided me with a local php.ini to test configuration changes. I've added the following to .htaccess (temporarily): # account-specific php.ini file <IfModule mod_suphp.c> suPHP_ConfigPath /home/[username] <Files php.ini> order allow,deny deny from all </Files> </IfModule> # disable mod_security <IfModule mod_security.c> SecFilterEngine Off SecFilterScanPOST Off </IfModule> In the php.ini file, I've set the following directives: suhosin.simulation = On always_populate_raw_post_data = -1 I've also set a specific directory for uploads: upload_tmp_dir = /home/[username]/tmp GD support is included. PW doesn't log any errors, even with $config->debug set to true. This is PW 2.7.3 on PHP 5.6.28. What else should I check?
  25. hey everyone, I use delayed output and a basic ajax structure, see below. My page has four containers: content, shows, header & footer. Any show that is clicked is now being loaded in the content area. Works great! Now I would like to have certain links to load in the show container, instead of the content container. Could anyone give me a hint how i could achieve that? I think i need two different ajax calls..? I need this to implement a sort function for the shows. I want to use $pages->get("/shows/")->children('sort=$sortvar'); thank you for your time! fira <?php $cajax = $config->ajax; if(!$cajax): include("_head.inc"); ?> <!-- content --> <div id="content"> <?php endif; // end if ajax ?> <?=$content?> <?php if(!$cajax): ?> </div> <!-- //content --> <div id="shows"> <a href="sortshows=location">sort by location</a> <a href="">show link</a> </div><!-- end shows --> <div id="footer"> </div> <?php endif; // end if ajax ?>
×
×
  • Create New...