The same data on all pages of pager - drupal

I wrote a pagination in my custom module, but the pager displays the same data on all its pages. My query has 4 elements. I want to display 2 elements per page. I use range(0,4) and it shows me all 4 elements on every page, I tried lots of combinations of range(). How can I display 2 elements per page? Please help :) My code:
public function news() {
$query = $this->entityTypeManager
->getListBuilder('node')
->getStorage()
->getQuery();
$query->condition('type', 'aktualnosc');
$query->condition('status', 1);
$result = $query->range(0, 4)->execute();
$nodes = $this->entityTypeManager->getStorage('node')->loadMultiple($result);
pager_default_initialize(count($result), 2);
$render = [];
$render[] = [
'#theme' => 'news',
'#results' => $nodes,
'#type' => 'remote'
];
$render[] = [
'#type' => 'pager',
'#quantity' => 2
];
return $render;
}

You made a tiny mistake, you always ::range() from 0 to 4 elements. Instead, you should use the ::pager() method instead.
Here is the same function as yours but using the pager instead of range.
public function news() {
$query = $this->entityTypeManager
->getListBuilder('node')
->getStorage()
->getQuery();
$query->condition('type', 'aktualnosc');
$query->condition('status', 1);
// Get all the aktualnosc nodes to initialize our pager.
$nids = $query->execute();
pager_default_initialize(count($nids), 2);
$query->pager($limit);
// Fetch nodes based on our pager.
$nids = $query->execute();
$nodes = $this->entityTypeManager->getStorage('node')->loadMultiple($nids);
$render = [];
$render[] = [
'#theme' => 'news',
'#results' => $nodes,
'#type' => 'remote'
];
$render[] = [
'#type' => 'pager',
'#quantity' => 2
];
return $render;
}

Related

How to add image to node programmaticly?

There is an entity in which I added the Image field. The database has a custom table with different columns, including the id of the images.
Previously, I created a batch that writes data from this table to entity fields. That is, it creates many entities from the records in the table with filled fields. I need to do the same but for images. Part of the code from the batch:
if (empty($entity_id)) {
$info = [
'type' => 'product',
'title' => $productTitle,
'field_name' => (string) $product->name,
'field_product_cid' => (string) $product->cid,
'field_custom_url' => $product->url,
'uid' => 1,
// here I need to add an image to the field_image field from the table
];
$node = $this->entityTypeManager->getStorage('node')->create($info);
$node->save();
}
else {
$storage = $this->entityTypeManager->getStorage('node');
$node = $storage->load($entity_id);
// Change fields of node.
$node->set('title', $productTitle);
$node->set('field_name', (string) $product->name);
$node->set('field_custom_url', $product->url);
// and here change field_image if the node already exists
$node->save();
}
}
Someting like this:
$node = $storage->load($entity_id);
$image_source_path = '/some/path'
$image_target_directory = 'public://some/path';
$image_data = file_get_contents ($image_source_path);
$image_alt = 'some alt text';
// Drupal 9 >= 9.3.0 or Drupal 10
$image_object = \Drupal::service('file.repository')
->writeData($$image_data, $image_target);
// Drupal 8
//$image_object = file_save_data ($image_data, $image_target);
$node->set('field_image', [
'target_id' => $image_object->id(),
'alt' => $image_alt,
]);
$node->save();

Drupal 7: custom module: display custom contentTypy in custom block

I'm new at Drupal 7, so I have a question.
I have my own content type Writers that includes such fields as Title, Years of life, Photo, Description.
I have a task to display 3 random Writers at page. Actual I've done it with help of Views module, but I want to do it myself.
So I created my own module random_content like that:
<?php
function random_content_help($path, $arg) {
switch ($path) {
case "admin/help#random_content":
return '<p>'. t("Displays random content") .'</p>';
break;
}
}
function random_content_block_info() {
$blocks['random_content'] = array(
'info' => t('Random content'),
'cache' => DRUPAL_CACHE_PER_ROLE,
);
return $blocks;
}
function random_content_contents() {
$query = db_select('node', 'n')
->fields('n', array('nid', 'title'))
->condition('type', 'writers')
->orderBy('rand()')
->range(0,3)
->execute();
return $query;
}
function random_content_block_view($delta = '') {
switch($delta){
case 'random_content':
$block['subject'] = t('Random content');
if(user_access('access content')) {
$result = random_content_contents();
$items = array();
foreach ($result as $node){
$items[] = array(
'data' => l($node->title, 'node/' . $node->nid) . '</br>',
);
}
if (empty($items)) {
$block['content'] = t('No data availible.');
} else {
$block['content'] = theme('item_list', array(
'items' => $items));
}
}
}
return $block;
}
As you can see, I've learned only to add links to particular content. But how can I display full information including Title, Years of life, Photo and Description?
To display the full node, or parts of it you need to load the node. E.g.
$my_node = node_load($nid);
$render_array = array();
$render_array['title'] = array(
'#type' => 'markup',
'#markup' => $my_node->title
);
$author = field_get_items('node', $my_node, 'field_author','und');
$render_array['author'] = array(
'#type' => 'markup',
'#markup' => $author[0]['safe_value']
);
// or as some like to do it
$render_array['author'] = array(
'#type' => 'markup',
'#markup' => $my_node->field_author['und'][0]['value']
);
echo drupal_render($render_array);
Note the 'und' constant means the language is undefined. If you have translation/language enabled and different content for different languages you would have to use 'en', 'de' etc. for the appropriate language.
You can also let drupal render the node and then manipulate or retrieve individual items. Like this
$my_node = node_load($nid);
$build = node_view($my_node,'full');
$build['body'][0]['#markup'] = $build['body'][0]['#markup'].' some addition';
$build['field_author'][0]['#markup'] = $build['field_author'][0]['#markup'].' my favorite';
echo drupal_render($build);
The advantage of using this latter method is that then the whole themeing engine kicks in, and all hooks that are set to act on the content etc. Of course, if you only want to retrieve values you don't need that.
Note also, I assume your author field is named field_author. You should check that in the field edit window for the content type.

Content filter does not search drupal7

I have added a drop down of my courses title at the filter second of the drupal - admin - content area.
http://www.XYZ.com/demo/admin/content
But when I select any of the title and hit Filter nothing gets appear. The data which showed previously it shows again, nothing happens really.
My code for the add filter drop down:
function products_form_node_admin_content_alter(&$form, &$form_state){
$results = db_query("SELECT r.nid, r.title FROM {node} AS n
LEFT JOIN {node_revision} AS r ON r.nid = n.nid
WHERE type = 'product'")->fetchAll();
$optionsF = Array ( '[any]' => 'any' );
foreach($results as $key => $result) {
$options[$result->title] = $result->title;
}
$options = $optionsF + $options;
$course_titles['title'] = Array
(
'#type' => 'select',
'#options' => $options,
'#title' => 'title',
'#default_value' => 'any'
);
$form['filter']['filters']['status']['filters'] = $form['filter']['filters']['status']['filters'] + $course_titles;
$uid_column = array('uniqueid' => array(
'data' => 'UniqueID',
'field' => 'n.nid'
));
$form['admin']['nodes']['#header'] = $form['admin']['nodes']['#header']+$uid_column;
foreach ($form['admin']['nodes']['#options'] as $key => $row) {
$node = node_load(array('nid' => check_plain($key)));
$form['admin']['nodes']['#options'][$key]['uniqueid'] = $node->field_unique_code_course['und'][0]['value'];
}
}
Does any body have any idea what is lacking in my code or method?
Cheers!!!
I would recommend using Admin Views, it's built for this purpose.
https://drupal.org/project/admin_views

drupal ajax form change

I'm working on a drupal 7 module, where I wish to print out infos on a page (MENU_LOCAL_TASK node/%node/something), with ajax filters.
I created a form and added 2 checkboxes, 1 is on default other is not. I want to show to the user the information according to wich checkbox is checked. 1 is on table row 1 is displayed, 2 is on table row 2 is displayed. If some of it is off, than that table row is off. Did I mentioned, that I want to solve it without submit and reload, only ajax.
I added to the two 'checkbox'es the following 'ajax' => array('callback' => 'my_module_callback')
. Here is the rest of the code, simplefied.
function my_module_callback($form, $form_state) {
$data = array();
$nid = 1;
if ($form_state['values']['checkbox1']) {
$data += load_data($nid, "checkbox1");
}
if ($form_state['values']['checkbox1']) {
$data += load_data($nid, "checkbox2");
}
$commands[] = ajax_command_html("#here", my_module_table($data));
return array('#type' => 'ajax', '#commands' => $commands);
}
function my_module_table($data){
//do some stuff with the data in a foreach
return theme("my_module_fancy_table",array("data" => $data));
}
function theme_my_module_fancy_table($data){ //registered with my_module_theme()
// putting html into $output in a foreach
return $output;
}
function my_module_page_callback_from_menu_function($nid){
$output = drupal_render(drupal_get_form('my_module_custom_ajax_form'));
$output .= "adding other stuffs including div#here";
return $output;
}
First of all is this the 'good way' to do this, cause I kind of lost confident:)
Second question, how to show the data on page load, rigth now one checkbox needs to be changed to see some infos.
Thanks and sorry for the short description :)
You should not really be doing the processing in the callback, it should be done in the form building function. The callback usually only returns the part of the form that has changed. Also, I don't think there is not need for setting commands[] in this case as returning part of the form will automatically replace the content set by 'wrapper'.
function my_module_form($form, $form_state){
$data = array();
$nid = 1;
if ($form_state['values']['checkbox1']) {
$data += load_data($nid, "checkbox1");
}
if ($form_state['values']['checkbox2']) {
$data += load_data($nid, "checkbox2");
}
$form = array();
$form['checkbox1'] = array(
'#type' => 'checkbox',
'#ajax' => array(
'callback' => 'my_module_callback'
'wrapper' => 'mydata',
'event' => 'change',
),
);
$form['checkbox2'] = array(
'#type' => 'checkbox',
'#ajax' => array(
'callback' => 'my_module_callback'
'wrapper' => 'mydata',
'event' => 'change',
),
);
$form['mydata'] = array(
'#prefix' => '<div id="mydata">',
'#suffix' => '</div>',
'#markup' => my_module_table($data),
);
return $form;
}
function my_module_callback($form, $form_state){
// $form_state['rebuild'] = true; may have to be set because the form has not been submitted and wont be rebuilt...I think, I cant remember for sure.
return $form['mydata'];
}
To show the data on page load, you just have to change the logic of setting data in the form build function.
Also, fyi, there is a stack site specifically for drupal at: http://drupal.stackexchange.com

Drupal: Parent-child draggable table

So I've been going at this one for a while now. I'm trying to create a draggable table that has a parent-child relationship, but where the children cannot be moved out of the parent group, and all of the parents are sortable among each other. I've modeled my form and theme off of the admin menu code, and I have it duplicating that functionality. The problem is that I can move the children to another parent, or let it become a parent. As an illustration:
Category 1
|
|--Item 1
|--Item 2
Category 2
|
|--Item 3
|--Item 4
|--Item 5
I would like to be able to sort Item 1 and Item 2 with each other, and Item 3, Item 4, and Item 5 with each other, but not move them between Category 1 and Category 2. I also need to be able to sort Category 1 and Category 2 with one another, taking the children with them. I've went through so many combinations of $action, $group, $subgroup settings mixed with $class settings for the categories and items that I've lost track. Nothing I have tried so far has produced the desired result. Here's the relevant bits of my code as it is currently:
In my form:
$form['#tree'] = true;
foreach($categories as $cat) {
if(!isset($form['categories'][$cat->cid])){
$form['categories'][$cat->cid] = array(
'weight' => array(
'#type' => 'weight',
'#delta' => 25,
'#attributes' => array('class' => array('item-weight', 'item-weight-' . $cat->cid)),
),
'cid' => array(
'#type' => 'hidden',
'#value' => $cat->cid,
'#attributes' => array('class' => array('cid')),
),
);
foreach($cats[$cat->cid] as $item) {
$form['categories'][$cat->cid]['items'][$item->id] = array(
'weight' => array(
'#type' => 'weight',
'#delta' => 25,
'#default_value'=> $item->weight,
'#attributes' => array('class' => array('item-weight', 'item-weight-' . $cat->cid)),
),
'cid' => array(
'#type' => 'hidden',
'#value' => $cat->cid,
'#attributes' => array('class' => array('cid')),
),
);
}
}
}
In my theme:
$children = element_children($form['categories']);
$rows = array();
if(count($children) > 0) {
foreach($children as $cid) {
$row = array(
drupal_render($form['categories'][$cid]['weight']) .
drupal_render($form['categories'][$cid]['cid']),
);
$rows[] = array(
'data' => $row,
'class' => array('draggable', 'tabledrag-root'),
);
foreach(element_children($form['categories'][$cid]['items']) as $id) {
$row = array(
theme('indentation', array('size' => 1)) . drupal_render($form['categories'][$cid]['items'][$id]['name']),
drupal_render($form['categories'][$cid]['items'][$id]['weight']) .
drupal_render($form['categories'][$cid]['items'][$id]['cid']),
);
$rows[] = array(
'data' => $row,
'class' => array('draggable', 'tabledrag-leaf'),
);
}
drupal_add_tabledrag('cat-table', 'order', 'sibling', 'item-weight', 'item-weight-' . $cid);
}
}
drupal_add_tabledrag('cat-table', 'match', 'parent', 'cid', 'cid', 'cid', true, 1);
$output = theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => 'cat-table')));
$output .= drupal_render_children($form);
return $output;
I've read over the documentation for drupal_add_tabledrag(), looked at the code, looked at example code, and searched around drupal.org and Google, but haven't come up with anything.
My only solution so far is to copy and modify the tabledrag.js file to just eliminate those capabilities, but while stopping the indent problem with the items (meaning, not letting them be on the same as the categories), keeping them in the same category has been Not Fun.
I suppose the most important question is, using standard Drupal is this possible?
I know you've already done a lot of coding so you might not want to give it up at this point, but DraggableViews is great to accomplish this. You can set up a normal view and add this draggableviews filter, it adds a weight and optionally a parent reference. The view itself uses the same drag-n-drop system as the rest of Drupal's backend tables.
Alternatively you can use a term reference and tie taxonomy terms to nodes, and just use that drag-n-drop.
If I'm missing something in your needs, my apologies, just thought I'd offer this simpler solution as it has definitely served me well in the past. Best of luck either way.
Just finished adding this functionality to my module
https://github.com/player259/ajax_table
There is no help, demo is outdated, but I'm working on it from time to time
Sections support was achieved by overriding tabledrag.js functions
Use this snippet to insert table
$form['map'] = array(
'#type' => 'ajax_table',
'#header' => array(t('Element'), t('Settings'), t('Weight')),
'rows' => array(),
'#draggable' => array(
// drupal_add_tabledrag will be called in theme layer
// NULL first arg to apply to this table
array(NULL, 'match', 'parent', 'perfect-form-parent', 'perfect-form-parent', 'perfect-form-index'),
array(NULL, 'depth', 'group', 'perfect-form-depth', NULL, NULL, FALSE),
array(NULL, 'order', 'sibling', 'perfect-form-weight'),
),
'#draggable_groups' => array(),
);
foreach ($map as $i => $element) {
// ... some logic
$form['map']['rows'][$i] = array(
'data' => array(
'element' => array(),
'settings' => array(),
'tabledrag' => array(
'index' => array(
'#type' => 'hidden',
'#value' => $element['data']['tabledrag']['index'],
'#attributes' => array('class' => array('perfect-form-index')),
),
'parent' => array(
'#type' => 'hidden',
'#default_value' => $element['data']['tabledrag']['parent'],
'#attributes' => array('class' => array('perfect-form-parent')),
),
'depth' => array(
'#type' => 'hidden',
'#default_value' => $element['data']['tabledrag']['depth'],
'#attributes' => array('class' => array('perfect-form-depth')),
),
'weight' => array(
'#type' => 'weight',
'#delta' => $max_weight,
'#default_value' => $weight,
'#attributes' => array('class' => array('perfect-form-weight')),
),
),
),
'#attributes' => array('class' => array($row_class_current, $row_class_child)),
);
// This means that row with $row_class_child class could have as parent
// only row with $row_class_parent class
// NULL means root - there are no parents
$form['map']['#draggable_groups'][$row_class_child] =
$depth ? $row_class_parent : NULL;
}
I had a similar problem at work so posting here my solution since none i found worked correctly in all situation. It is done 100% in javascript, on the php side you just have to set tabledrag in match with parent on pid and sort with siblings on weight.
The current code work on the example module (tabledrag parent/child) to adapt it to your need, change the .example-item-pid by your class for the PID input field. You just need to add it to the example code to have it working and see if it corresponds to your need.
First function invalidate any attempt to drop elements that don't have the same parent (PID) than the target element.
Second Function bypass the dragRow function to drop the element in the correct place (= the last children of the target row) and at the right depth ( = same depth than the target row).
/**
* Invalidate swap check if the row target is not of the same parent
* So we can only sort elements under the same parent and not move them to another parent
*
* #override Drupal.tableDrag.row.isValidSwap
*/
// Keep the original implementation - we still need it.
Drupal.tableDrag.prototype.row.prototype._isValidSwap = Drupal.tableDrag.prototype.row.prototype.isValidSwap;
Drupal.tableDrag.prototype.row.prototype.isValidSwap = function(row) {
if (this.indentEnabled) {
if (row && $('.example-item-pid', this.element).val() !== $('.example-item-pid', row).val()) {
return false;
}
}
// Return the original result.
return this._isValidSwap(row);
}
/**
* Position the dragged element under the last children of the element target for swapping when moving down our dragged element.
* Removed the indentation, since we can not change parent.
* #override Drupal.tableDrag.row.dragRow
*/
Drupal.tableDrag.prototype.dragRow = function (event, self) {
if (self.dragObject) {
self.currentMouseCoords = self.mouseCoords(event);
var y = self.currentMouseCoords.y - self.dragObject.initMouseOffset.y;
var x = self.currentMouseCoords.x - self.dragObject.initMouseOffset.x;
// Check for row swapping and vertical scrolling.
if (y != self.oldY) {
self.rowObject.direction = y > self.oldY ? 'down' : 'up';
self.oldY = y; // Update the old value.
// Check if the window should be scrolled (and how fast).
var scrollAmount = self.checkScroll(self.currentMouseCoords.y);
// Stop any current scrolling.
clearInterval(self.scrollInterval);
// Continue scrolling if the mouse has moved in the scroll direction.
if (scrollAmount > 0 && self.rowObject.direction == 'down' || scrollAmount < 0 && self.rowObject.direction == 'up') {
self.setScroll(scrollAmount);
}
// If we have a valid target, perform the swap and restripe the table.
var currentRow = self.findDropTargetRow(x, y);
if (currentRow) {
if (self.rowObject.direction == 'down') {
/**
* When going down we want to position the element after the last children and not right under the currentRow
*/
// create a new row prototype with currentRow
var rowObject = new self.row(currentRow, 'mouse', self.indentEnabled, self.maxDepth, false);
// extract all children
var childrenRows = rowObject.findChildren();
// if we have children
if (childrenRows.length > 0) {
// we change the row to swap with the last children
currentRow = childrenRows[childrenRows.length - 1];
}
self.rowObject.swap('after', currentRow, self);
}
else {
self.rowObject.swap('before', currentRow, self);
}
self.restripeTable();
}
}
/**
* We have disabled the indentation changes since it is not possible to change parent.
*/
return false;
}
};

Resources