AngularJS add css class if item selector variable is true - css

I have an item selector directive and I want to add a test for the selected item : if it's archived I have to add a css class.
.directive-items-selector{ ng_click: "openItemsSelector( $event )" }
.wrapper
%ui_select.ui-select{ ng: { model: "input.model", disabled: "disabled",
change: "itemSelectModelChanged()" },
search_enabled: "{{ options.searchable }}" }
%ui_select_match.ui-select-match{ items_selector_match: '',
placeholder: "{{ input.placeholder }} ",
allow_clear: "{{ options.clearable }}",
title: "{{ $select.selected.label }}" }
%i.fa{ ng_class: 'icon' }
{{ $select.selected.label }}
{{$select.selected.object.is_archived}}
%ui_select_choices.ui-select-choices{ repeat: "item.id as item in input.filteredItems track by item.id",
refresh: "reloadItems( $select.search )",
refresh_delay: '{{ input.filterDelay }}' }
.item{ ng_attr_title: "{{ ::item.label }}" }
.item-label {{ ::item.label }}
%small.item-details {{ ::item.details }}
.items-selector-actions
%a.pointer.action{ ng: { if: 'linkToModal', click: 'openDetails()', disabled: "!model" }}
{{ 'btn.details' | translate }}
%a.pointer.action{ ng: { if: 'createButton && klassName && !disabled', click: 'createItem()' }}
{{ 'btn.new' | translate }}
the {{$select.selected.object.is_archived}} return true if the item is archived, I don't know how to add this css class ! any help

You can us the ng-class directive like this:
ng-class="{'class-false' : selected.object.is_archived, 'class-true' : }"
https://docs.angularjs.org/api/ng/directive/ngClass

Related

Handlebars - accessing `this` within a conditional statement with #root

Is there any way to access this within a conditional?
To explain a bit moreā€¦ I have a loop over some items. I want to conditionally show the price if another value is set to something.
{
"firstName": "Terry",
"showPrice": "yes",
"items": [
{ "itemName": "Item 1", "itemPrice": "23.99" },
{ "itemName": "Item 2", "itemPrice": "50.99" }
]
}
{{#each items }}
<p>{{ this.itemName }}</p>
{{#equals #root.showPrice "yes"}}
<p>{{ this.itemPrice }}</p>
{{/equals}}
{{/each}}
The issue seems to be due to going back to the #root to check against the showPrice value, it then breaks this being accessible.
I've tried things like:
{{ this.itemPrice }} // doesn't work
{{ #root.this.itemPrice }} // doesn't work
{{ #root.items.this.itemPrice }} // doesn't work
{{ #root.items.[0].itemPrice }} // can now access, but only the 0 index
{{ #root.items.#index.itemPrice }} // doesn't work
Does anyone have any ideas?

Check if a custom Twig function exists and then call it

I test if a custom Twig function exists:
{% if methodExist('sg_datatables_render') %}
{{ sg_datatables_render(datatable) }}
{% else %}
{{ datatable_render((datatable)) }}
{% endif %}
methodExist is a simple Twig_Function:
/**
* #param $name
* #return bool
*/
public function methodExist($name){
if($this->container->get('twig')->getFunction($name)){
return true;
}else{
return false;
}
}
But I get an exception:
Unknown "sg_datatables_render" function. Did you mean "datatable_render"?
500 Internal Server Error - Twig_Error_Syntax
I tried to replicate this, and indeed, {{ sg_datatables_render(datatable) }} seems to always cause a Twig_Error_Syntax exception when sg_datatables_render has not been registered as a Twig function.
I then tried something like this. It's ugly, but I wanted to know if it works. The idea is that a non-existing function will be created to avoid the exception being thrown:
$twig->addFunction(new Twig_Function('methodExist', function(Twig_Environment $twig, $name) {
$hasFunction = $twig->getFunction($name) !== false;
if (!$hasFunction) {
// The callback function defaults to null so I have omitted it here
return $twig->addFunction(new Twig_Function($name));
}
return $hasFunction;
}, ['needs_environment' => true]));
But it didn't work. I also tried to add a simple callback function to the new function with no success.
I tried the same trick with filters, i.e.:
{% if filterExists('sg_datatables_render') %}
{{ datatable|sg_datatables_render }}
{% else %}
{{ datatable|datatable_render }}
{% endif %}
It didn't work either.
Solution 1: {{ renderDatatable(datatable) }}
Something like this does work (yay!):
$twig->addFunction(new Twig_Function('renderDatatable', function(Twig_Environment $twig, $datatable) {
$sgFunction = $twig->getFunction('sg_datatables_render');
if ($sgFunction !== false) {
return $sgFunction->getCallable()($datatable);
}
return $twig->getFunction('datatable_render')->getCallable()($datatable);
}, ['needs_environment' => true]));
And then in Twig:
{{ renderDatatable(datatable) }}
The renderDatatable function is specific to rendering datatables, i.e. it's not a general/multipurpose function like your methodExist is, but it works. You can of course try to create a more general implementation yourself.
Solution 2: {{ fn('sg_datatables_render', datatable) }}
Here's a more general approach. Create an additional Twig function to accompany methodExist:
$twig->addFunction(new Twig_Function('fn', function(Twig_Environment $twig, $name, ...$args) {
$fn = $twig->getFunction($name);
if ($fn === false) {
return null;
}
// You could add some kind of error handling here
return $fn->getCallable()(...$args);
}, ['needs_environment' => true]));
Then you could modify your original code to this:
{% if methodExist('sg_datatables_render') %}
{{ fn('sg_datatables_render', datatable) }}
{% else %}
{{ datatable_render((datatable)) }}
{% endif %}
Or even use the ternary operator:
{{ methodExist('sg_datatables_render') ? fn('sg_datatables_render', datatable) : datatable_render(datatable) }}
PS
Here's how I'd write the methodExist function:
$twig->addFunction(new Twig_Function('methodExists', function(Twig_Environment $twig, $name) {
return $twig->getFunction($name) !== false;
}, ['needs_environment' => true]));
I added s to the end of the function's name because the function checks whether a method/function exists.
I added ['needs_environment' => true] so I can use $twig instead of $this->container->get('twig'). (Kudos to yceruto for this tip.)
getFunction returns false if the function doesn't exist (see the docs), so I simplified the function body to a single-line return statement.

How to define map[string]object in yaml?

How to define map[string] object in YAML?
I have JSON object
{
"name": "SampleStore",
"books": {
"sample1": {
"author": "test1",
"prize": "1221"
},
"sample2": {
"author": "test2",
"prize": "890"
}
}
}
I had defined object in YAML as:
Types:
store:
name:
type: String
books:
Items:
Referemce: book_details
book_details:
author:
type: String
prize:
type: String
But this is syntax for list, I want map of book. How to define these type of map in YAML?
You should take a look at this:
stores:
-
name: SampleStore
books:
-
sample1:
author: test1
prize: 1221
-
sample2:
author: test2
prize: 1221
And you can try to run with this:
{%for store in stores %}
{{ store.name }}
{{ store.books|length }}
{%for book in store.books %}
{{ book }}
{% endfor %}
{% endfor %}
Will produce the output:
SampleStore
2
Array
Array
You could play with it at this link
I would suggest you to use a key for the book title also in order to facilitate the access (something like name: sample1).
Hope this help

Add array elements into variable in Twig

I stored some settings in array in Twig and I need to store them into some variable so I can print it. My array contains some data attributes like this:
{% set data = {
visible: { data: "data-visible-items", value: options.visible_items },
scroll: { data: "data-itemes-scroll", value: options.items_to_scroll },
speed: { data: "data-animation-speed", value: options.animation_speed },
infinite: { data: "data-infinite", value: options.infinite },
autoplay: { data: "data-autoplay", value: options.autoplay_enable },
interval: { data: "data-autoplay-interval", value: options.autoplay_interval },
hover: { data: "data-autoplay-hover", value: options.autoplay_hover },
} %}
Simply I want to store everything from array in one variable, in this variable it's need to be stored like this (separator is space) for example:
data-visible-items="5" data-items-scroll="2" data-animation-speed="400" data-infinite="0" data-autoplay="1" data-autoplay-interval="3000" data-autoplay-hover="1"
So, if the variable is for example attributes I just want to print it like this:
<div{{ attributes}}>
// Content
</div>
I wrote for loop like this:
{% for item in data %}
{{ item.data }} {{ item.value }}
{% endfor %}
and it will print each data and value, but how to store this in the variable in the way I described above?
If you want to store into a variable you can do this:
{% for item in data %}
{% set myvar = item.data ~ ' ' ~ item.value %}
{% endfor %}
If you want to transform that array you could make use of a Twig_Filter or Twig_Function
just chain http_build_query
PHP
$twig->addFunction(new Twig_SimpleFunction('http_build_query', http_build_query', ['is_safe' => [ 'html', ],]));
Twig
<div{{ http_build_query(attributes, '', ' ') }}>
Create the string yourself with a foreach
PHP
$twig->addFilter(new Twig_SimpleFilter('build_attribute_list', function (array $array) {
$str = '';
foreach($array as $key => $val) $str .= ' '.$key.'="'.$val.'"';
return $str;
}, ['is_safe' => ['html'],]);
Twig
<div{{ attributes|build_attribute_list }}>
(edit) Needless to say you can store the output in a variable as well
{% set my_var = attributes|build_attribute_list %}
{{ my_var }}

Drupal 8 jQuery is undefined in module twig view

I am trying to develop my first Drupal 8 module and I cannot understand why jQuery is undefined in my twig template.
In my block I call controller function:
public function build() {
$config = $this->getConfiguration();
$slider = new OsTouchController;
return $slider->displaySlider($config['id']);
}
Then in controller:
public function displaySlider($slider_id) {
$oss_params = $this->getSliderParams($slider_id);
return array(
'#theme' => 'slider_default',
'#oss_params' => $oss_params,
'#attached' => array(
'library' => array(
'ostouch_slider/ostouch.slider'
),
),
);
}
and finally in twig I have such script code:
jQuery(document).ready(function($) {
var mySliderSetings = new osSliderSettings("#dragable-settings-block",{
crop : {{ oss_params.crop_image }},
parallax : {{ oss_params.parallax }},
imageWidth: {{ oss_params.image_width }},
imageHeight: {{ oss_params.image_height }},
site_path : '{{ "http://" }}',
moduleId : {{ oss_params.modId }},
lazyLoading : {{ oss_params.lazyLoading }},
lazyLoadingInPrevNext : {{ oss_params.lazyLoadingInPrevNext }},
lazyLoadingInPrevNextAmount : {{ oss_params.lazyLoadingInPrevNextAmount }},
textOrdering: {{ oss_params.textOrdering }},
screenW : screenW,
screenH : screenH,
setupAnimation : setupAnimation,
swiperSlider : mySwiper
});
});
Of course I get an error:
"Uncaught ReferenceError: jQuery is not defined"
because all scripts includes are in the bottom of the page.
I can't find function for script which can help me to display my script code in the bottom of the page.
I can't write this code in js file because params in script can changes.
I can read params from hidden input but I think in Drupal exist another way...
Who can help me? What I did wrong?
Use Drupal.behaviors instead of document.ready. Read about it HERE.
eg.
Drupal.behaviors.myBehavior = {
attach: function (context, settings) {
var mySliderSetings = new osSliderSettings("#dragable-settings-block",{
crop : {{ oss_params.crop_image }},
parallax : {{ oss_params.parallax }},
imageWidth: {{ oss_params.image_width }},
imageHeight: {{ oss_params.image_height }},
site_path : '{{ "http://" }}',
moduleId : {{ oss_params.modId }},
lazyLoading : {{ oss_params.lazyLoading }},
lazyLoadingInPrevNext : {{ oss_params.lazyLoadingInPrevNext }},
lazyLoadingInPrevNextAmount : {{ oss_params.lazyLoadingInPrevNextAmount }},
textOrdering: {{ oss_params.textOrdering }},
screenW : screenW,
screenH : screenH,
setupAnimation : setupAnimation,
swiperSlider : mySwiper
});
}
};

Resources