Multi Level Block Method Is Generating Issue

Multi level block method is generating issue

First of all we refactored your helper for more intensive usage of content_tag (just to get whats going in this code ^_^).

Next we add usage of output_buffer which was defined but not used at all in helper.

After it all methods wich should be called from erb should return nil so they didn't appear in HTML.

And last syntactic suger was usage of instance_eval so you don't need {|c| ...} style blocks. You can use all variables from DataListBuilder directly there.

module DataListHelper
def list_headers(args=[])
args = Array.new(args)
columns = []
args.map { |o| columns << content_tag(:li, o.split(":").first, :style=>"width:#{o.split(":").second}px;") }
content_tag(:ul, columns.join(" ").html_safe, :class=>"list-headers")
end

def data_list_total_records(array)
content_tag(:div, page_entries_info(array).html_safe, :class=>"total-records")
end

def data_list_for(object, headers=[], &block)

if object.is_a? Array
if object.length == 0
list_headers(headers).concat(content_tag(:strong, "<br />No records found".html_safe))
else
res_obj = data_list_total_records(object)
res_obj << content_tag(:ol, :class=>"data-list") do
res_ol = content_tag(:li) do
res = list_headers(headers)
object.each do |o|
builder = DataListBuilder.new(o)
res << content_tag(:li) do
content_tag(:ul, :id=>o.id, :class=>"list-row #{cycle('odd', 'even')}") do
capture(builder, &block)
builder.output_buffer.html_safe
end
end
end
res
end
res_ol << data_list_pagination(object)
end
res_obj
end
else
list_headers(headers).concat(content_tag(:strong, " <br />Not available."))
end
end

class DataListBuilder
include ActionView::Helpers::TagHelper
include ActionView::Helpers::CaptureHelper
include ActionView::Helpers::UrlHelper
include Rails.application.routes.url_helpers

attr_accessor :object, :output_buffer, :controller

def initialize(object)
@object, @output_buffer = object, ''
end

def column (&block)
@output_buffer << if block_given?
content_tag(:li, instance_eval(&block))
else
content_tag(:li, "")
end
nil
end

def options_column(&link_block)
@output_buffer << if block_given?
content_tag(:li) do
content_tag(:dl, :class=>'options') do
res = content_tag(:dt) do
content_tag(:a, ' '.html_safe, :href => '#')
end
res << content_tag(:dd) do
content_tag(:ul) do
instance_eval &link_block
end
end
end
end
else
content_tag(:li, "")
end
nil
end

def link_item(title, url, options={})
content_tag :li, link_to(title, url, options)
end
end
end

And your view became this:

<%= data_list_for @leads, [" :10", "Age:30", "Contact:140", "Phone:140", "Email:180", "Company:100", ""] do |l| %>
<%= l.column { link_to " ".html_safe, "leads/details/#{object.id}", :class=>:plus, :remote=>true } %>
<%= l.column { object.age } %>
<%= l.column { object.contact.complete_name } %>
<%= l.column { object.contact.phones.blank? ? "-" : object.contact.phones.first.phone_number } %>
<%= l.column { object.contact.emails.blank? ? "-" : object.contact.emails.first.email } %>
<%= l.column { object.company.title } %>
<%= l.options_column do %>
<%= link_item 'Show', lead_path(object.id) %>
<%= link_item 'Edit', edit_lead_path(object.id) %>
<%= link_item 'New Note', "leads/#{object.id}/notes/new", :class=>"display-newxdoc", :id=>object.id %>
<%= link_item 'Create Opportunity', new_lead_opportunity_path(object.id) %>
<% end %>
<% end %>

Jinja2 Multi-level template inheritance issue

I understand your issue: you've got template A, template B (extends template A), and template C (extends template B). There's a block defined in template A, but it's not showing up in the page that uses template C, unless you define that block in template B. If you do that, then the block in question shows up.

First: you are correct in your understanding that this is not how the Jinja template hierarchy is supposed to work. Second, I did not encounter your issue (found a different one, though), and I have constructed a proof to demonstrate this. Here's what I did (again, using Python 3 and Django 1.11):

$ python startproject myapp

In the myapp/myapp/settings.py file, I updated the template engine:

TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [
os.path.join(BASE_DIR, 'myapp/templates') # hack / should add `myapp` to INSTALLED_APPS instead
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

In myapp/myapp/urls.py, I created a dummy view function & route:

from django.conf.urls import url
from django.shortcuts import render_to_response

def home(request):
return render_to_response('dashboard.html')

urlpatterns = [
url(r'^$', home),
]

And finally, I established those templates, but I removed the call to import your macros, along with all instances of static().

Here is the myapp/myapp/templates/skeleton.html file:

<!doctype html>
<html lang="en">
<head>
{% block head_content %}
<meta charset="utf-8">
<title> {% if page_title %} {{ page_title }} | {% endif %} Bhargavi Books & Stationery </title>
{% endblock head_content %}
</head>

<body>
<div id="navigation">
{% block navigation %}
<div class="ui three item menu">
<a class="active item">Home</a>
<a class="item">New Bill</a>
<a class="item">View Bills</a>
</div>
{% endblock navigation %}
</div>

<div id="frame">
{% block frame_content %}
<p> Body content goes here. Body for {{ content_name }}</p>
{% endblock frame_content %}
</div>

<div id="app">
{% block app_content %}
<p> APP content goes here. Body for {{ content_name }}</p>
{% endblock app_content %}
</div>

{% block scripts %}
{% endblock scripts %}
</body>
</html>

Here is the myapp/myapp/base.html file:

{% extends "skeleton.html" %}

{% block frame_content %}
Frame Content
{% endblock frame_content %}

{% block scripts %}
{{ super() }}
{% endblock scripts %}

And here is the myapp/myapp/templates/dashboard.html file:

{% extends "base.html" %}

<div>
{% block body_content %}
Body 3
{% endblock body_content %}
</div>

<div>
{% block app_content %}
DASHBOARD
{% endblock app_content %}
</div>

And here is the output, after viewing that page in my browser:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> Bhargavi Books & Stationery </title>
</head>

<body>
<div id="navigation">
<div class="ui three item menu">
<a class="active item">Home</a>
<a class="item">New Bill</a>
<a class="item">View Bills</a>
</div>
</div>

<div id="frame">
Frame Content
</div>

<div id="app">
DASHBOARD
</div>
</body>
</html>

Since this all works as expected*, my conclusion is that you might have a problem with the base.html template file. Perhaps it's failing to import your macros, and subsequently not behaving correctly? I notice a trailing comma in there, and I'm not sure if that could be problematic or not. I would suggest using the above code as a starting point, and then slowly add back in the parts that I stripped out, and perhaps the problem will become visible/understandable.

*One thing I found odd, that I don't understand: the body_content block is completely missing from my output, unless I define that block in the skeleton.html template. It doesn't work if I define it in the base.html template, which seems wrong to me, because then we're not really extending that second template (base.html)... so there does seem to be something weird there... but I was not able to encounter the original issue you described, so maybe this will be helpful in that particular regards, at least.

Multi-level drop down menu in CSS not working properly

To fix the position of the submenu, and prevent the size of the item at the main menu to change, you can do as follows:

give the submenu (ul element- can be what you declared as .menu ul li ul):

  • position:absolute
  • padding:0 (the built-in padding of the ul element is what you called "margin of unknown origin")
  • left:100% to set the submenu location.
  • top:0 to set the submenu location.

give it's parent (li element- can be what you declared as .menu li)):

  • position:relative

As for the last issue, personally I think using "nth-child" for your case is not a good choise- I whould prefer using a dedicated class for active item.

But if you want to solve what you did here, just be more specific about what item you want to style:
instead of this selector: .menu ul li:nth-child(2),
use this selector: .menu > ul > li:nth-child(2).
so the style will be applied to the second direct li child of the main menu only.

Facing Css issue in multi Level Menu

The CSS should be targeting only the child element whose parent has .active class,

.active > app-submenu > ul {
display: block !important;
}

We need to modify the app.component and submenu.component (both HTML and TS)

Now to make this work on clicking the parent elements, we need a variable which will tell us which li is selected, we can use data attribute of the element to save its state, instead of creating a new variable.

<li [attr.data-selected]="false"> /* content */ </li>

and to access it we give an angular ID to the element and pass it as arguement in the NgClass

<li #thisLiElement [attr.data-selected]="false" [ngClass]="setActiveClass(thisLiElement)"> /* content */ </li>

Now the data attribute needs to be updated when clicked upon.

<li *ngFor="let menu of navItems" (click)="clickedEvent($event); $event.stopPropagation();" #thisLiElement [attr.data-selected]="false" [ngClass]="setActiveClass(thisLiElement)">

The defination for clickedEvent and setActiveClass are as follows, which toggles on current elements dataset

clickedEvent(event){
if (event.currentTarget["dataset"].selected === "false")
event.currentTarget["dataset"].selected = "true";
else
event.currentTarget["dataset"].selected = "false";
}

setActiveClass(thisLiElement) {
return thisLiElement.dataset.selected === "true" ? { "active": true } : { "active": false };
}

Note: The mat-icon if conditions should be also updated for above change as follows

<mat-icon *ngIf="menu.children && menu.children.length > 0">{{iconState(thisLiElement)}}</mat-icon> 

and the defination for iconState should be,

iconState(thisLiElement) {
return thisLiElement.dataset.selected === "true" ? "expand_less" : "expand_more";
}

Also there is no need for @output in submenu component, so i have removed the emitter and the function subMenuClicked

Updated StackBlitz over here.

Hope it helps.

Testing for Adjacent Cells In a Multi-level Grid

  • I actually have 5 levels not 2, so I could potentially get a list like "A8A1A, A8A1B, B1A2A, B1A2B".
  • Adding a new cell to compare still requires me to compare all the other cells before it (seems like the best I could do for this step is
    O(n))
  • The cells aren't all 3x3 blocks, they're just that way for my example. They could be MxN blocks with different M and N for different
    levels.

I don't see a problem with these points: if a cell is not adjacent at the highest level one then we can stop the computation right there and we don't have to compute adjacency at the lower levels. If there are only five levels then you'll do at most five adjacency computations which should be fine.

  • In my current implementation above, I have separate functions to check adjacency if the cells are in the same blocks, if they are in separate horizontally adjacent blocks or if they are in separate vertically adjacent blocks. That means I have to know the position of the two blocks at the current level before I call one of those functions for the layer below.

You should try to rewrite this. There should only be two methods: one that computes whether two cells are adjacent and one that computes whether two cells are adjacent at a given level:

  • RelativePosition isAdjacent(String cell1, String cell2);
  • RelativePosition isAdjacentAtLevel(String cell1, String cell2, int level);

The method isAdjacent calls the method isAdjacentAtLevel for each of the levels. I'm not sure whether cell1 or cell2 always contain information of all the levels but isAdjacent could analyze the given cell strings and call the appropriate level adjacency checks accordingly. When two cells are not adjacent at a particular level then all deeper levels don't need to be checked.

The method isAdjacentAtLevel should do: lookup M and N for the given level, extract the information from cell1 and cell2 of the given level and perform the adjacency computation. The computation should be the same for each level as each level, on its own, has the same block structure.

Setup of multi-level and dependent observables

You can achieve the desired result the mergeMap operator.

import { mergeMap, map } from 'rxjs/operators';

createAndGetAntity(result) {
return this.service.createAndGetEntity(result.data.order).pipe(
mergeMap((response: EntityResponse<OrderModel>) => {
if (result.data.unknownLocation) {
if (result.data.isRedundant) {
return this.secondService.createWithRedundancy(someData);
} else {
return this.secondService.createEntity(someData);
}
}
return of(true);
}),
map(() => true),
);
}

I would handle dispatching the success and error actions in the subscribe block, and not in the service method itself.

this.service.dispatchErrorAction(result).subscribe(
(order) => this.dispatchSuccessAction(order),
(err) => this.dispatchErrorAction(err)
)


Related Topics



Leave a reply



Submit