I want to generate a multilevel hierarchical select option that is indented right as we move from parent to child. I tried using recursion in PHP(CI) for this but can't generate what I needed.
This is the function I tried to generate the select option.
<?php
$category_list = $this->helper_model->get_category();
/* $category list contains
[{"id":"1","name":"Information Technology","parent_id":"0"},
{"id":"2","name":"Programming","parent_id":"1"},
{"id":"3","name":"Civil","parent_id":"5"},
{"id":"4","name":"Networking","parent_id":"1"},
{"id":"5","name":"Engineering","parent_id":"0"},
{"id":"6","name":"Electrical","parent_id":"5"},
{"id":"11","name":"Hardware","parent_id":"1"},
{"id":"12","name":"Car Driver","parent_id":"13"},
{"id":"13","name":"Driver","parent_id":"0"},
{"id":"14","name":"java","parent_id":"2"},
{"id":"15","name":"javascript","parent_id":"2"}]
*/
$select_option = $this->multilevel_select($category_list);
echo '<select name = "subCategory">
<option>Select Category</option>' . $select_option;
function multilevel_select($array,$parent_id = 0,$parents = array()) {
static $i=0;
if($parent_id==0)
{
foreach ($array as $element) {
if (($element['parent_id'] != 0) && !in_array($element['parent_id'],$parents)) {
$parents[] = $element['parent_id'];
}
}
}
$menu_html = '';
foreach($array as $element){
if($element['parent_id']==$parent_id){
$menu_html .= '<option>';
for($j=0; $j<$i; $j++) {
$menu_html .= '—';
}
$menu_html .= $element['name'].'</option>';
if(in_array($element['id'], $parents)){
$i++;
$menu_html .= $this->multilevel_select($array, $element['id'], $parents);
}
}
}
$i=0;
return $menu_html;
}
?>
Can anyone help me get through this?
Related
I've created a products categories tables which contain data here in this table have both parent and it children by the ways I'm doing is work as well but it simply messy and not much better with many function that I have to call for each categories levels so I want to get some help to find out the better and easy way to filter all it children and get the same as below images result.
I think function that I have create really the same so it should have some better way revise and make it better than this one.
Here is my Helper function
<?php
namespace app\Helpers;
use App\Http\Controllers\Admin\AdminController;
final class Helper extends AdminController
{
public function setData($data)
{
return $this->data = $data;
}
final public function GetCats($selection = null, $name = null)
{
$html = '<select name="'.$name.'" class="'.$selection.'" >';
foreach ($this->data as $key => $cats) {
if ((int)$cats->parent_id === 0) {
foreach ($cats->CategoryDescriptions as $d) {
$html .= '<option>';
$html .= $d->name.$this->getChild1($cats->id, $d->name);
$html .= '</option>';
}
}
}
$html .= '</select>';
echo $html;
}
private function getChild1($category_id, $parentName) //-->
{
$childs = '';
foreach ($this->data as $child) {
if ((int)$child->parent_id == (int)$category_id) {
foreach ($child->CategoryDescriptions as $d) {
$childs .= '<option>' .$this->myspace(). $parentName . ' -> ';
$childs .= $d->name.$this->getChild2($child->id,$parentName, $d->name);
$childs .= '</option> ';
}
}
}
return $childs;
}
private function getChild2($category_id,$parentName,$name1) //-->
{
$childs = '';
foreach ($this->data as $child) {
if ((int)$child->parent_id == (int)$category_id) {
foreach ($child->CategoryDescriptions as $d) {
$childs .= '<option>'.$this->myspace().$parentName.' --> '.$name1.' --> ';
$childs .= $d->name.$this->getChild3($child->id, $parentName, $name1,$d->name);
$childs .= '</option>';
}
}
}
return $childs;
}
private function getChild3($category_id, $parentName, $name1,$name2) //-->
{
$childs = '';
foreach ($this->data as $child) {
if ((int)$child->parent_id == (int)$category_id) {
foreach ($child->CategoryDescriptions as $d) {
$childs .= '<option>'.$this->myspace().$parentName.' --> '.$name1.' --> '.$name2.' --> ';
$childs .= $d->name.$this->getChildn4($child->id, $parentName, $name1,$name2,$d->name);
$childs .= '</option>';
}
}
}
return $childs;
}
private function getChildn4($category_id, $parentName, $name1, $name2,$name3) //-->
{
$childs = '';
foreach ($this->data as $child) {
if ((int)$child->parent_id == (int)$category_id) {
foreach ($child->CategoryDescriptions as $d) {
$childs .= '<option>'.$this->myspace().$parentName.' --> '.$name1.' --> '.$name2.' --> '.$name3.' --> ';
$childs .= $d->name.$this->getChildn5($child->id, $parentName, $name1,$name2,$name3,$d->name);
$childs .= '</option>';
}
}
}
return $childs;
}
private function getChildn5($category_id, $parentName, $name1, $name2, $name3,$name4) //-->
{
$childs = '';
foreach ($this->data as $child) {
if ((int)$child->parent_id == (int)$category_id) {
foreach ($child->CategoryDescriptions as $d) {
$childs .= '<option>'.$this->myspace().$parentName.' --> '.$name1.' --> '.$name2.' --> '.$name3.' --> '.$name4.' --> ';
$childs .= $d->name.$this->getChildn5($child->id, $parentName, $name1,$name2,$name3,$d->name);
$childs .= '</option>';
}
}
}
return $childs;
}
private function myspace (){
return ' ';
}
}
Call this is class and method in View
<?PHP
$helper = new Helper();
$helper->setData($cat);
$helper->GetCats('col-lg-9','cats');
?>
Result:
This is my current array that displays list items in a unordered list.
function get_bottle_colors() {
if(empty($_GET['cap_id'])) return false;
$constructor_img = get_post_meta($_GET['cap_id'], 'product_constructor_image', true);
if(is_array($constructor_img) && count($constructor_img)>0 && !empty($constructor_img[0]['title'])){
$output = '<label>Bottle Color</label><ul>';
foreach ($constructor_img as $key => $image) {
if(empty($image['image'])) continue;
$output .= '<li><a href="'.$image['image'].'" data-width="'.$img_size[0].'" data-height="'.$img_size[1].'"';
$output .= '</a></li>';
}
$output .= '</ul>';
}else{
$output = '<label>Bottle Color</label><ul></ul>';
}
echo $output;
die();
}
In total there will be up to 16 list items generated by this. I need each list item to have its own class eg: list class="red", list class="green", etc. Any idea how i go about achieving this?
Found the solution thanks to Anant. Had to declare the class array like below.
function get_bottle_colors() {
if(empty($_GET['cap_id'])) return false;
$constructor_img = get_post_meta($_GET['cap_id'], 'product_constructor_image', true);
if(is_array($constructor_img) && count($constructor_img)>0 && !empty($constructor_img[0]['title'])){
$output = '<label>Bottle Color</label><ul>';
$i = 0;
$class_array = array("a","b","c","d","e","f","g","h","i","j","k","l","n","m","n","o","p");
foreach ($constructor_img as $key => $image) {
if(empty($image['image'])) continue;
$category = 9;
$img_size = getimagesize($image['image']);
$output .= '<li class= "'.$class_array[$i].'"><a href="'.$image['image'].'" data-width="'.$img_size[0].'"
data-height="'.$img_size[1].'"';
$output .= 'data-id="'.$_GET['cap_id'].'_'.$key.'" data-part="#constructor-bottles" class="sub-caps">'.$image['title'];
$output .= '</a></li>';
$i++;
}
$output .= '</ul>';
}else{
$output = '
<label>Bottle Color</label><ul></ul>'; } echo $output; die(); }
I am trying to make nested categories in Laravel. I have created following models: Category.php, ItemsHelper.php (this one for displaying nested categories).
ItemsHelper.php:
class ItemsHelper {
private $items;
public function __construct($items) {
$this->items = $items;
}
public function htmlList() {
return $this->htmlFromArray($this->itemArray());
}
private function itemArray() {
$result = [];
foreach($this->items as $item) {
if ($item->parent_id == 0) {
$result[$item->title] = $this->itemWithChildren($item);
}
}
return $result;
}
private function childrenOf($item) {
$result = [];
foreach($this->items as $i) {
if ($i->parent_id == $item->id) {
$result[] = $i;
}
}
return $result;
}
private function itemWithChildren($item) {
$result = [];
$children = $this->childrenOf($item);
foreach ($children as $child) {
$result[$child->title] = $this->itemWithChildren($child);
}
return $result;
}
private function htmlFromArray($array) {
$html = '';
foreach($array as $k => $v) {
$html .= "<ul>";
$html .= "<li>" . $k . "</li>";
if(count($v) > 0) {
$html .= $this->htmlFromArray($v);
}
$html .= "</ul>";
}
return $html;
}
}
Then i am printing nested list of data in my index.blade.php:
{{ $itemsHelper->htmlList() }}
However this prints only plain titles and i need to convert them in to a links to my category, e.g. htmlFromArray() method:
$html .= "<li>" . $k . "</li>";
method itemArray():
$result[$item->title] = $this->itemWithChildren($item);
How can i add to this array id of each item?
You should probably change methods itemArray, itemWithChildren and htmlFromArray this way:
private function itemArray()
{
$result = [];
foreach ($this->items as $item) {
if ($item->parent_id == 0) {
$record['title'] = $item->title;
$record['id'] = $item->id;
$record['children'] = $this->itemWithChildren($item);
$result[] = $record;
}
}
return $result;
}
private function itemWithChildren($item)
{
$result = [];
$children = $this->childrenOf($item);
foreach ($children as $child) {
$record['title'] = $child->title;
$record['id'] = $child->id;
$record['children'] = $this->itemWithChildren($child);
$result[] = $record;
}
return $result;
}
private function htmlFromArray($array)
{
$html = '';
foreach ($array as $item) {
$html .= "<ul>";
$html
.=
'<li><a href="/category/' . $item['id'] . '">' . $item['title']
. "</a></li>";
if (count($item['children']) > 0) {
$html .= $this->htmlFromArray($item['children']);
}
$html .= "</ul>";
}
return $html;
}
Now you can store in your arrays id, title and list of element children so you can access iun htmlFromArray all those elements attributes.
Hello im trying to achieve this
http://phpfiddle.org/main/code/jw3-s1j
Actually i think its working fine.. But you CANT difference between a category and a subcategory like in the example before..
So how can i have a select box with a tree inside???
<?PHP
$result = mysql_query("SELECT id, parent_id, name FROM category")or trigger_error('Query failed: ' . mysql_error(), E_USER_ERROR);; // This line executes the MySQL query that you typed above
$datas = array(); // make a new array to hold all your data
while($row = mysql_fetch_assoc($result)) {
$datas[] = $row;
}
function generatePageTree($datas, $depth = 0, $parent = 0){
if($depth > 1000) return ''; // Make sure not to have an endless recursion
$tree = '';
for($i=0, $ni=count($datas); $i < $ni; $i++){
if($datas[$i]['parent_id'] == $parent){
$tree .= str_repeat('-', $depth);
$tree .= '<option value=\''.$datas[$i]['name'] . '\'>'.$datas[$i]['name'] . '</option><br/>';
$tree .= generatePageTree($datas, $depth+1, $datas[$i]['id']);
}
}
return $tree;
}
echo '<select>';
echo(generatePageTree($datas));
echo '</select>';
?>
Solved!!
Fixed Code:
function generatePageTree($datas, $depth = 0, $parent = 0){
if($depth > 1000) return ''; // Make sure not to have an endless recursion
$tree = '';
for($i=0, $ni=count($datas); $i < $ni; $i++){
if($datas[$i]['parent_id'] == $parent){
$tree .= str_repeat('-', $depth);
$tree .= '<option value=\''.$datas[$i]['name'] . '\'>'.str_repeat('-', $depth).$datas[$i]['name'] . '</option><br/>';
$tree .= generatePageTree($datas, $depth+1, $datas[$i]['id']);
}
Solved!!
Fixed Code:
function generatePageTree($datas, $depth = 0, $parent = 0){
if($depth > 1000) return ''; // Make sure not to have an endless recursion
$tree = '';
for($i=0, $ni=count($datas); $i < $ni; $i++){
if($datas[$i]['parent_id'] == $parent){
$tree .= str_repeat('-', $depth);
$tree .= '<option value=\''.$datas[$i]['name'] . '\'>'.str_repeat('-', $depth).$datas[$i]['name'] . '</option><br/>';
$tree .= generatePageTree($datas, $depth+1, $datas[$i]['id']);
}
$tree = taxonomy_get_tree($vid);
print "<li>"; // 1 line
foreach ($tree as $term ) { // 2 lines
$diffdepth=0;
if ($term->depth > $depth) {
print "<ul class='haschild'><li>";
$depth = $term->depth;
}
the above is the original code, now I want according to $term->depth > $depth make a condition to output.( print "<li>"; ) this line.
namely,
if ($term->depth > $depth) {
echo '<li class="parent">';
}
else {
print "<li>";
}
but $term->depth can use after foreach loop, but i want to use it at 1 line, how do i do?
Instead of printing in-line, assign your desired output to variables and then send it to the browser after the logic is complete.
$tree = taxonomy_get_tree($vid);
$parent = ""; // 1 line
$child = "";
foreach ($tree as $term) { // 2 line
$diffdepth=0;
if ($term->depth > $depth) {
$parent = "<li class='parent'>";
$child .= "<ul class='haschild'><li>";
$depth = $term->depth;
} else {
$parent = "<li>";
}
}
echo $parent . $child;
Please note you'll need to finish this up by adding all the applicable </li>s and whatnot, but this should get you started.
Use a counter:
$tree = taxonomy_get_tree($vid);
$counter = 0;
foreach ($tree as $term)
{
...
if ($term->depth > $depth)
{
if ($counter == 0) { echo '<li class="parent">'; }
else { echo '<li>'; }
print "<ul class='haschild'><li>";
$depth = $term->depth;
}
...
$counter++;
}
If you need to write more differences based on your condition, you can turn tha above into:
$tree = taxonomy_get_tree($vid);
$counter = 0;
foreach ($tree as $term)
{
...
if ($term->depth > $depth)
{
if ($counter == 0) { echo '<li class="parent">'; }
print "<ul class='haschild'><li>";
$depth = $term->depth;
}
else
{
if ($counter == 0) { echo '<li>'; }
...
}
...
$counter++;
}
if you want to build something like parent child hierarchy then you should check it by click here