I start using Agile Toolkit about 2 hours ago and I can't solve one problem:
I need to add pagination to the main page of the blog and to the category page, that's my way:
$lister = $this->add('Lister_Paginated',null,'Posts','Posts');
$lister->setSource('posts');
$lister->dq->where('published = FALSE')->order('date',true);
$lister->addPaginator(5);
template file
<?Posts?>
<?rows?>
<?row?>
<div class="post">
<img src="/uploads/img/<?previewIMG?>empty.jpg<?/?>" width="180" height="182"/><br />
<span class="postTitle"><?title?>Заголовок поста<?/?></span>
</div>
<?/row?>
<?/rows?>
<?$paginator?>
<?/Posts?>
But paginator doesn't work (content doesn't change)
There is no such a method in Lister. You should just take this method form here and add into your project Lister
lib/Lister/Paginated.php
class Lister_Paginated extends CompleteLister {
public $paginator;
function addPaginator($ipp = 25, $options = null) {
// adding ajax paginator
if ($this->paginator) {
return $this->paginator;
}
$this->paginator = $this->add('Paginator', $options);
$this->paginator->ipp($ipp);
return $this;
}
function defaultTemplate() {
return array('view/lister/paginated');
}
}
view/lister/paginated.html
<<?element?>ul<?/?> class="atk-lister <?$class?>" id="<?$_name?>">
<?rows?>
<?row?>
<<?row_element?>li<?/?> class="atk-lister-row <?$odd_even?>">
<h3><?$name?></h3>
</<?row_element?>li<?/?>>
<?/row?>
<?totals?>
<<?row_element?>li<?/?> class="atk-lister-totals">
Total: <?$row_count?> row<?$plural_s?>
</<?row_element?>li<?/?>>
<?/totals?>
<?/rows?>
<?$Content?>
<?$paginator?> <---------------------------
</<?element?>ul<?/?>>
Usage:
$lister = $this->add('Lister_Paginated');
$lister->->addPaginator();
Which class do you use Lister or CompleteLister?
Don't use addPaginator cause it's quite old. Use $lister->add('Paginator')->ipp(2); It works with CompleteLister just fine.
Related
I'm using livewire with pagination. I set the input to defer so that the search is not carried out until the search button is clicked. However, I have also noticed that if I have any text in the search box that value is sent whenever a pagination button is clicked. I've tried setting the value to "" in jquery $(document).on("click", ".page-link", () => $( "#inlineFormInput" ).val("")); when a pagination buttton is click but that has not solved the problem. And actually clearing the value could cause other problems.
The desired result is that, if for some reason a user leaves text in the searchbox that value is not passed if the user changes their mind and just clicks a pagination link. The input value should only be passed when the search button is clicked. Any help would be greatly appreciated.
livewire component html:
<div id="searchBoxRow">
<input wire:model.defer="search" wire:keydown.enter="updateFaculty" id="inlineFormInput" class="form-control" val="" type="search" autocomplete="off" placeholder="Seach for Name or Country" aria-label="Search">
<button wire:click="updateFaculty" class="btn btn-primary" id="facultyCardsSearchButton" type="submit">
<i class="bi bi-search button-icon"></i>
<span class="button-text">Search</span>
</button>
</div>
livewire php file:
<?php
namespace App\Http\Livewire;
use App\Models\Tag;
use App\Models\Faculty;
use Livewire\Component;
use Livewire\WithPagination;
class FacultyData extends Component
{
use WithPagination;
protected $paginationTheme = 'bootstrap';
public $search = null;
public $tagId = null;
public function updateFaculty(){
$search = $this->search;
$tagId = $this->tagId;
$this->emit('closeAutocomplete');
}
public function updatingSearch()
{
$this->resetPage();
}
public function render()
{
$tags = Tag::all();
$allFaculty = Faculty::searchFilter([$this->search, $this->tagId])->with('country', 'tags')->paginate(10);
return view('livewire.faculty-data', [
'allFaculty' => $allFaculty,
'tags' => $tags
]);
}
}
Here is an idea. You can use the updatingPage() of the $page property hook. When performing the page switch clean the search property. But, somehow you need to check if this is a result of a searched data before or just the client has had his way...well, my idea is get a flagged property to tell livewire what to do. For example
public $searchFlag = false;
public function updateFaculty(){
if ($this->search) // only of search has any value
$this->searchFlag = true;
// do
}
public function updatingPage()
{
if (! $this->searchFlag) {
$this->reset(['search']);
}
if (! $this->search) {
$this->reset(['searchFlag']);
}
}
Hi fellow stackoverflowers,
I am running repeatedly into following issue while digging myself into Laravel8 Livewire capabilities. In my Livewire component called Ticker I am reading a series of dates data from a calendar table into a component property $days.
In my view I am displaying a div element for each element of $days with a wire:click, which should wire to the component's tick() method.
The view renders and mounts fine, but each time an element is clicked, a "Trying to get property 'id' of non-object $day->id" error appears - as if the $days property had been deleted or emptied by the method call. Can anyone help me in understanding this behaviour?
Component Ticker.php:
class Counter extends Component
{
public $days;
public function mount()
{
$this->days = \DB::table("caldays")->WhereBetween("id", [320, 326])->get();
}
public function render()
{
return view('livewire.ticker');
}
public function tick($id)
{
/* do stuff with selected $id */
}
}
View ticker.blade.php:
...
#foreach($days as $day)
<div class="border border-light-blue-500 border-opacity-75 p-6 text-center"
wire:click="tick({{ $day->id }})"
>
#endforeach
...
Many thx in advance & happy year & stay healthy!
You have to notice that. After delete your respective day this will not update your collection anyway. So after deletion you have to re query the days.Or Simply remove the respective day from your collection.
Try This:
#forelse($days as $day)
<div class="border border-light-blue-500 border-opacity-75 p-6 text-center"
wire:click="tick({{ $day->id }})"
>
#empty
<p>No day found</p>
#endforelse
Another solution is:
#if(count($days>0)
#foreach($days as $day)
<div class="border border-light-blue-500 border-opacity-75 p-6 text-center"
wire:click="tick({{ $day->id }})"
>
#endforeach
#endif
In php file:
public function tick($dayId){
$day = \DB::table("caldays")->Where("id", $dayId)->get();
$day->delete();
if(in_array($dayId,$this->days)) {
$key = array_search($dayId, $this->days);
array_splice($this->days, $key, 1);
}
}
I've built my module and made an AdminController that list items from my table, with creation/update/delete/view.
In the listing page, I'd like to add a message after the breadcrumb, but before the table.
I saw there is a hook available : "displayAdminListBefore" and a block to extend "override_header", but I don't know how to make it work!
Can someone could point me in the right direction please?
You can simply add your module to the displayAdminListBefore hook.
First hook the module to this hook with the install function:
public function install()
{
if (!parent::install() || !$this->registerHook('displayAdminListBefore'))
return false;
return true;
}
Then create the hook function like that:
public function hookDisplayAdminListBefore($params)
{
return '
<div class="bootstrap">
<div class="alert alert-success">
<button data-dismiss="alert" class="close" type="button">×</button>
Add your text here
</div>
</div>
';
}
Or, you can also use a .tpl:
public function hookDisplayAdminListBefore($params)
{
$this->smarty->assign(array(
'first_var' => $first_var,
'second_var' => $second_var',
));
return $this->display(__FILE__, 'views/templates/admin/listbefore.tpl');
}
The best way for you will be to override list_header.tpl and use the override_header hook.
To do so, create a new file list_header.tpl in modules/your_module/views/templates/admin/your_module/helpers/list/list_header.tpl
In this file copy the following code:
{extends file="helpers/list/list_header.tpl"}
{block name="override_header"}
Your text
{$your_var}
{/block}
$your_var must be defined in your controller in the function renderList():
$this->context->smarty->assign(
array(
'your_var' => 'your_var_value'
)
);
I am working on my own javascript library. The library has a getAttr() function that operates like this:tex(selector).getAttr(name); Here is the library's code:
(function(){
var tex = function(s){
return new tex.fn.init(s);
};
tex.fn = tex.prototype ={
init : function(s){
if(!s){
return this;
}
else{
this.length = 1;
if (typeof s === "object"){
this[0] = s;
}
else if(typeof s === "string"){
var obj;
obj = document.querySelector(s);
this[0] = obj;
}
return this;
}
}
}
tex.fn.init.prototype = tex.fn;
tex.fn.init.prototype = {
attr : function(name, value){
/*if(name && !value){
return this[0].getAttribute(name);
}else if(name && value){
this[0].setAttribute(name,value);
};*/
this[0].setAttribute(name,value);
},
getAttr : function(name){
return this[0].getAttribute(name);
},
removeAttr : function(name){
this[0].removeAttribute(name);
},
print : function(txt){
this[0].innerHTML = txt;
}
};
window.TechX = tex;
})();
Here is the code in the body section:
<nav>
<ul>
<li><a id="MainDropper">Pick your method:</a>
<ul>
<li><a>book</a>
<ul>
<li><a data-val="Book" href="javascript:setType(this)">Book</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
And here is my code in the head section:
function setType(obj){
tex("#MainDropper").print(tex(obj).getAttr("data-val"));
}
So when I click the book link the mail dropper should have the text "Book." But instead I get an error in the library that says, "the [object global] has no method getAttrribute." Does anyone know how I can fix this problem?
Thank you so much.
The credit should really go to Bergi, but in the interest of providing an answer, here goes.
When you use a listener like:
<a onclick="code" ... >
then the content of the onclick attribute is effectively wrapped in a function that is called with the element as this, like:
function listener(){code}
listener.call(element);
However, when the href attribute and javascript pseudo–protocol (aka "javascript: URL scheme") are used the code is executed as global code, so more or less just:
code;
HTML5 says to behave as if a new script element was inserted with the code as content. So within the listener function (execution context), this will reference the global (window) object.
Note that browser behaviour can differ here (e.g. variables declared in javascript URLs) as there was no specification for how such code should be treated until HTML5, which really just tries to specify one version of what browsers already do. Previously, it was left as part of DOM 0*, which was all the DOM stuff that browsers did before W3C specifications that was not made part of new specifications.
* DOM 0 is "…a mix (not formally specified) of HTML document functionalities offered by Netscape Navigator version 3.0 and Microsoft Internet Explorer version 3.0." W3C DOM Level 1 01-Oct-1998.
It's thick o'clock on Monday afternoon...
How do I add a pager to a projection list?
I have a list of 135 Recorded Species content items that comply with a Query. So how do I page them? :(
Checking Show Pager box in the Edit Projection page just adds:
<< Older Newer >>
links at the bottom of the page. The html rendered is, for example:
<ul class="group pager" shape-id="3">
<li class="page-next" shape-id="3">« Older
</li>
<li class="page-previous" shape-id="3">Newer »
</li>
</ul>
Ie:
<< Older increases the page number. Newer >> decreases the page number. This looks like a bug to me, as I would expect Previous and Next links, as well as page number links. Not older and newer...
Is there some module that needs disabling?
This is a feature: the default frontend pager is just like that (page 1 is always the newest page).
For a richer pager just take a look at the one in the TheAdmin theme (Views/Pager). This below is a stripped down version of it, displaying also the page numbers:
#{
Model.PreviousText = T("<");
Model.NextText = T(">");
var routeData = new RouteValueDictionary(ViewContext.RouteData.Values);
var queryString = ViewContext.HttpContext.Request.QueryString;
if (queryString != null)
{
foreach (string key in queryString.Keys)
{
if (key != null && !routeData.ContainsKey(key))
{
var value = queryString[key];
routeData[key] = queryString[key];
}
}
}
if (routeData.ContainsKey("id") && !HasText(routeData["id"]))
{
routeData.Remove("id");
}
Model.Metadata.Type = "Pager_Links";
IHtmlString pagerLinks = Display(Model);
Model.Classes.Add("selector");
var pageSizeTag = Tag(Model, "ul");
if (Model.RouteData != null)
{
foreach (var rd in Model.RouteData.Values)
{
routeData[rd.Key] = rd.Value;
}
}
}
#if (Model.TotalItemCount > 1)
{
<div class="pager-footer">
#pagerLinks
</div>
}