Jump to content

kongondo

PW-Moderators
  • Posts

    7,529
  • Joined

  • Last visited

  • Days Won

    160

Everything posted by kongondo

  1. Thanks for responding @ryan. No, the error was triggering later, on line 41, at the JSON.parse(). I just found it strange that removing the class .InputfieldPage made the error go away. No, I didn't try this. Next time. That's what I was thinking at first. However, if I added multiple fields, it would reload the first one OK then trip on the next one. Yeah, me too! ?.
  2. Output formatting is off when in ajax mode...
  3. I have got this sorted, but I don't think it will help you @AndZyk. In my case, after adding fields to an inputfield (similar to a repeater), I was manually reloading a pagefield inputfield that uses InputfieldTextTags like this: $myInputfieldTextTagsSelectItem.trigger("reloaded") That was throwing up the JavaScript error I posted above. My remedy was to let ProcessWire Inputfields trigger the reload, like this: // @note: reload() is a method in Inputfields.js Inputfields.reload($myInputfieldTextTagsSelectItem) Error gone! ?
  4. I did, only like a a hundred times ?. Maybe I was refreshing the wrong site! I'll give this a go. Thanks for sharing! And the pointers as well.
  5. I have managed to find the code that is causing the issue. In InputfieldTextTags.js, at the end of the file, the css class '.InputfieldPage' was added, changing the code from this (GitHub 3.0.183 ) // InputfieldTextTags.js ProcessWire 3.0.183 jQuery(document).ready(function($) { InputfieldTextTags(); $(document).on('reloaded', '.InputfieldTextTags', function() { InputfieldTextTags($(this)); }); }); to this (GitHub 3.0.184 ) // InputfieldTextTags.js ProcessWire 3.0.184 jQuery(document).ready(function($) { InputfieldTextTags(); $(document).on('reloaded', '.InputfieldTextTags, .InputfieldPage', function() { // <= '.InputfieldPage' addition causing error(?) InputfieldTextTags($(this)); }); }); I have no solution at the moment ?.
  6. Just confirming that for me, the issue is not present in 3.0.183. Will now try to narrow it down to changed files in 3.0184.
  7. @AndZyk, @ryan I can confirm this (?). I have been having a similar issue since I upgraded to 3.0.184 when it was still in dev. Back then, I just assumed the issue was the code in my module. I have since confirmed that by downgrading to 3.0.181, the issue goes away. I'll dig further to find out when it was introduced and what is causing it. In my situation, I am trying to reload/init a fieldset that has been added to an inputfield via ajax. The fieldset contains a multi page field that used Text Tags as the inputfield type. Here's the screenshot of the error: The 'u' token comes from an 'undefined' string in what was supposed to be the JSON response. The use ajax options is not enabled under Text Tags for the page field. I am on WAMP. Thanks.
  8. Just noting that I managed to resolve this (non-Tracy-related) problem. My script was getting sucked inside the pw panel markup due to loading order. All I had to do was to move my script markup before my pw panel markup. No more warnings, unnecessary ajax calls, etc ?.
  9. Great! I did the same and it refused to work. No errors, nothing. Nothing in the nav is getting picked up and nothing in the markup. How did you go about this? Thanks.
  10. Hi @adrian, I've debugged this further and the issue has nothing to do with Tracy (was just caught in the middle!), sorry. The issue persists even with Tracy disabled. It is a jQuery issue. No idea how I'll get around this. I have to load Alpine.js inline since (AFAIK) $config->scripts() does not support 'defer' which Alpine needs. Thanks.
  11. Correction. This actually seems to be the issue, sorry. I am calling alpine.js in an inline script. All that code lives inside a pw-panel. When I use the code outside a pw-panel, I get no warnings. When used inside a pw-panel, I get the warning, unless I don't refer alpine.js. So, it seems alpine js and jQuery are clashing somehow. I'll try set up a test environment, but it might take a couple of days. Thanks for looking into the matter.
  12. In my case dev tools says the initiator is JqueryCore.js, so that could be it, although I have no <script> tags in that part of the code. JqueryCore is calling alpine.js in this case. Sorry, no joy.
  13. Hi @adrian, I am using a custom pw-panel and on page load, the first time I hover over its 'open' button, I get the following JavaScript warning in the console: [Deprecation] Synchronous ?id=1083&s=1&c=1&_tracy_bar=js&v=2.8.3&XDEBUG_SESSION_STOP=1:485 XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/. I haven't investigated it much but it seems on hover, pw-panel loads the html inside the panel, which in this case has alpine.js attributes. Here's the debug screenshot from the console: Any ideas? Thanks.
  14. Apologies for the delay folks. Here you go: Demo code for Using htmx to Refresh ProcessWire Frontend Content.
  15. Sorry folks, I've been tied up. Will do so later today. If you mean the whole page (i.e. including, e.g. the site menu, etc), then what @netcarver said. die() will also work. Yes, if in a module halt() will not work. In some contexts, another process might be returning content as well. If exit() does not work for you, please show us your whole code and/or tell us more about your context.
  16. Is there a reason why you cannot follow this same pattern in the present project? I can see how this will be painful in the long run. It is also prone to mistakes; posts being added in the wrong sub-sub-category. What comes to mind is a custom module. Could be a process module or a runtime inputfield coupled with a Pages Save Hook. You probably won't even need to save they dynamic field as it is only there to help you drill down to the final parent of the post you are creating. An inputfield may not help with the challenge of going via the tree. It may even confuse authors as they will click on a parent page in the tree to 'Add' a post but the post will then be re-parented. So, maybe a process module is more friendly in this regard. At the top, you would have a dynamic select like field to drill down to sub-sub-category you want. It would then reveal a post add form. On create page, post author is redirected to the edit page of that post. The challenge here is that you will be working away from the usual page edit form. You will need to embed ProcessPageEdit::execute() output in your form. It is not difficult to do. There are posts in the forum that show you how. Just some preliminary thoughts...
  17. Erm, sorry, no. I am even more confused now. But maybe it's just me ?. I don't really understand what you mean by 'placed/published'. It seems to me that you want the editing actions on the right image (editing of a page with a dynamic field in it) to affect the ProcessWire tree in the left image. Is this correct? If this is your goal, then I think you have somehow misunderstood how this module works. It does not affect your publishing or ProcessWire tree. Am I missing something here? In your right image, I see you are already publishing the new post (My new post) and the parent (category) you want, i.e. 'Math'. I don't understand what you need dynamic selects to do in this case. My understanding was that you wanted one of the below: Select a POST in a dynamic select and it will show you all of that post's CATEGORIES. E.g. Selecting My Post 1 will show you Math. This is possible using the group relationship. Select a CATEGORY in a dynamic select and it will show you all of that category's POSTS. E.g. Selecting Math will show you My Post 1 and My Post 2. This you already do as shown in the left image, when you select Math. Am I on track with these assumptions? Sorry if I am taking you round in circles!
  18. Thanks, this is clearer. One thing still remains unclear. I don't understand what you mean by tree hierarchy in admin. Are you referring to the ProcessWire admin pages tree? If yes, then, no, dynamic selects cannot change your admin tree structure. I have a feeling this is not what you meant. If not, what tree are you referring to and how and where are you building it? Or, do you mean creating a dynamic selects in the backend/admin that will subsequently be used in a frontend template to display a 'tree' in a page in the frontend? Meaning, is the 'Subjects' tree as show in your example an illustration of how it should look like in the frontend (as opposed to the ProcessWire admin tree)? Hope my question is clear :-).
  19. Thanks for the purchase! ?. I don't fully understand this use case...Are you trying to build a menu? When I get a minute, I'll respond to your other post in MenuBuilder ?. Yes, this should work since Dynamic Selects will return the current value of a given field (any supported field as per its documentation). I may have misunderstood your use case/question though, so please clarify if this is the case.
  20. Here you are getting a single page ($pages->get). You are looping through it and the value in each loop is a value of a property in that page. These will mainly be strings (e.g. 'My page title') or integers, but there could be a Pageimages in there as well, if your page template has an images field. Either way, 'My page title'->url does not exist since this is a string (a non-object), hence the notice. This selector returns a collection, a PageArray. When you loop through it, each value in the loop is a Page object. Hence, $pageInLoop->url works. Although it starts with a $pages->get, the chaining of ->children ends up with getting the children of "/", i.e. a PageArray.
  21. Sorry to hear this. A little bit more information would help, i.e.: ProcessWire version. Multi or single language site. PHP version. Steps to reproduce, unless you mean you got that error right after the module installation finished. Thanks.
  22. Sure... If you haven't read deeply into htmx, the main premise is that the server is the single source of truth regarding both data and markup, i.e. whole application state. If we need to update either data or markup, the server handles that. We just need to tell it what action to take. Validation has to pass, of course, before the server will oblige ?. Below is a quick example that demonstrates updating the markup using htmx based on user actions. Only 'remove' locations is demonstrated in this example. I wasn't sure whether your app shows the user both their removed and added locations and whether they can reset the session to have all locations reloaded afresh. It doesn't matter much as it wouldn't change much of the logic in the example. Secondly, note that this example makes use of alpine.js and tailwind css just for the pizzaz. These are not required by htmx. To let ProcessWire recognise htmx requests, please refer to this thread. Depending on the approach you take from there, you might not even need a JavaScript file! In the example below, we do have a JavaScript file just because we want to use alpine.js (for notifications) and we need htmx to talk to alpine.js. We also need the JavaScript file to tell htmx to add XMLHttpRequest to its request headers so that ProcessWire's $config->ajax will understand the request. First, let's see a demo then we'll see how easy our work is using htmx. Just for this demo, I have included htmx (and alpine.js and tailwind css via their respective CDNs [in production, you want to purge your tailwind css ?]) in my _main.php. Inside the template I am using for this demo, I have the following code. Here, I have removed the tailwind classes used in the demo so we can focus on htmx. Note that you don't need a dedicated template file for this to work. It will work with any template. As long as htmx is loaded in the page view and your template (in this case, the current page's template) is listening to ajax requests. In the template file, the main htmx magic happens here: <?php namespace ProcessWire; $out = "<a hx-post='./' hx-target='#locations' hx-vals='{\"location_add_id\": \"{$page->id}\"}' hx-include='._post_token' hx-indicator='#locations_spinner_indicator'>Add</a>" . "<a hx-post='./' hx-target='#locations' hx-vals='{\"location_remove_id\": \"{$page->id}\"}' hx-include='._post_token' hx-indicator='#locations_spinner_indicator'>Remove</a>"; echo $out; Let's go through the htmx attributes: hx-post This tells htmx where to send its ajax request. In this case, we are sending it to the same page we are viewing (./) and are using POST. We could have used hx-get if we wanted to (GET). hx-target This tells htmx which markup to replace/swap. The default is to replace the markup of the element from which htmx was called. However, hx-target can be used to specify the element to replace. In this example, we are replacing the whole listing so we target its wrapper element which has the id locations. hx-vals This is optional but we need it in our example. We want to tell the server which location (ID) has been added/removed. If we had a form element, we could have used it for this instead. Since we don't have one, we are telling htmx to process the (JSON) value of hx-vals and send that together with its request. Note: the escape slashes are so we can have raw, valid JSON in the attribute as required by htmx. hx-include This is also optional but important in our case. It tells htmx to include input elements found via the selector in this attribute in its ajax request. In our example, we are telling htmx to include the CSRF token we set on the server together with its request. hx-indicator Also optional. Tells htmx to show/hide this element to show the user that something happened. In this case we use a spinner. We could have used a progress indicator as well, .e.g., if we were uploading a file. That's it really! No event listeners, no handlers! We can add (and I did add one), event listeners on htmx events in order to do something after the event. In this example, htmx fires a custom event which alpine.js is listening to in order to show notifications after the DOM has settled. The notification type (success, error, etc) and the message are all coming back from the server but not as JSON. The markup to update the page is also coming back from the server. htmx receives it and plugs it into the DOM per the hx-target (also see hx-swap) attribute value. In this example, we are updating the whole listing. If we wanted, we could update just the location that was removed, e.g. add it back but with some removed 'indicator', e.g. greyed-out. In this example we use anchor tags as htmx triggers. For htmx, it doesn't matter; button, div, p, li, whatever valid HTML element would work. You already have a backend logic that's working for you but I show an excerpt of mine here, for completeness. Inside my-template-file.php (the template file for the template for the current page, in this example), I have the following code: <?php namespace ProcessWire; if ($config->ajax) { // check CSRF if (!$session->CSRF->hasValidToken()) { // form submission is NOT valid throw new WireException('CSRF check failed!'); } // ................ more code // e.g. check removed locations in the session, etc // get previously removed locations (keeping things in sync) $removedLocations = $session->get('removedLocations'); // REMOVING LOCATION if ((int) $input->post->location_remove_id) { $mode = 'remove'; $notice = "Removed"; $id = (int) $input->post->location_remove_id; } else if ((int) $input->post->location_add_id) { // ADDING LOCATION $mode = 'add'; $notice = 'Added'; $id = (int) $input->post->location_add_id; } // ................ more code // e.g. check if we really have a page by that id, SET $noticeType, $options and update session 'removedLocations' etc // build final content //----------- // @note: buildLocationsCards() is a function that does what it says on the tin. We use it in both the ajax response here and also below, in non-ajax content, when the page loads // the $options array contains a key 'skip_pages_ids' with an array of IDs of locations (pages) that have been removed in this session. We skip these in buildLocationCards(). $out = buildLocationCards($page, $options); // @note - here we always return one input only // we use the values in this input in JS to pass event details to alpine.js to show the correct notification and the notification message. $out .= "<input type='hidden' id='location_notice' name='location_notice' data-notice-type='{$noticeType}' value='{$notice}'>"; echo $out; $this->halt(); } // NON-AJAX CONTENT BELOW.... That's all there is to it ?. I am happy to share the full code if anyone wants to play with this further.
  23. Just throwing in htmx as an alternative here. If you are interested, I could put together a rough example.
  24. You have several possibilities depending on whether you are looping through items or whether you just needed a single item from your items. Here are examples of both scenarios. Inside a loop <div> <!-- getGridItems here is a function that returns the current grid items --> <template x-for="(item, index) in getGridItems"> <!-- bind id to item id and its text to item state --> <span :id='item.id' x-text='item.state' :key="index"></span> </template> </div> Get One Item Several possibilities here: // use filter and since expecting only one item, get it at the first array index const myItem = items.filter((item) => item.id === itemId)[0]; // loop let myItem; for (const item of items) { if (item.id === itemId) { // you have found your item myItem = item; // break out of your loop break; } } // find const myItem = items.find((item) => item.id === itemId); // do some sanity checks here before using myItem For more on loops and iteration, have a look at the Mozilla docs. Depending on the app you are building, you might want to keep a caniuse tab open ?. I see that you are storing tagName (div, etc), meaning you are creating elements on the fly? You can use vanilla JS for this or depending on the number of element possibilities (div, span, ...n), you could use a number of x-ifs. Note, though, that there is no x-else in Alpine. The flatter an object, usually the easier your work. However, sometimes this is not always possible. To access nested data, again, you have several options. You could create a function that returns the object property you want. You can also use either of brackets or dot notation (myItem.breakpoints.base.css.color). However these can get messy if the nesting is very deep. Maybe you could flatten the breakpoints object since really, it is all mainly CSS? It would make it easier to bind styles to an element.
  25. Have you tried this? <?php $_SERVER['X-Shopify-Topic'];
×
×
  • Create New...