AngularJS / HAML : Add CSS class if property is true - angularjs

I work in customizing element of an ItemSelector directive, data of ItemSelector coming from rails server.
here is the haml code :
.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 }}
%i.archived.fa.fa-archive{ ng_if: '$select.selected.object.is_archived' }
%span.archived{ translate: 'archived.yes' }
%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 }}
I test if the object selected is archived or not by :
$select.selected.object.is_archived
for now I'm adding an icon and a small text to tell user that this object selected is archived, what what I want is to change that and add
text-decoration: line-through red; to be like that :
how to add css class depend on $select.selected.object.is_archived value

Ng-class accepts object, where key is your class and value is condition, when it is to be applied:
ng-class="{'desiredClass': $select.selected.object.is_archived}"
Or another solution is using ternary operator:
ng-class="$select.selected.object.is_archived ? 'desiredClass' : ''"
In HAML, via various usages:
%div{'ng-class': "{'desiredClass': condition === true}"}
%div{'ng_class': "{'desiredClass': condition === true}"}
%div{'ng': {'class': "{'desiredClass': condition === true}"}}
Here working codepen example:
https://codepen.io/anon/pen/pKreGv?editors=1010

Related

Best way to conditionally override an item value in an Ansible loop

I'm attempting to adapt an existing play that was built for automating account creation and deletion in a small environment without centralized authentication. Since then the scope has expanded and we've added bastion servers where it's not appropriate for all accounts to be created.
Because user IDs are hard coded (not desirable - I know) I'd like to avoid having a separate play for the bastions as that means keeping track of UIDs in two places. My workaround was to add an onbastion boolean to each row, then use that in create-account.yml to flip the state to absent if applicable. I originally tried changing the value of item.state directly but ran into syntax errors that I couldn't figure out. So I added a set_fact task to set the value of a new variable conditionally, but the playbook now fails with a message that "The task includes an option with an undefined variable. The error was: 'desired_item_state' is undefined".
What am I missing, and is there a better way to tackle this? Thanks in advance!
Relevant Snippets
project/roles/create-accounts/default/main.yml
users:
- { name: "user_1", id: 15001, state: "present", groups: ["project"], onbastion: true }
- { name: "user_2", id: 15002, state: "present", groups: ["project"], onbastion: true }
- { name: "fired_user_3", id: 15003, state: "absent", groups: [], onbastion: false}
- { name: "retired_user_4", id: 15004, state: "absent", groups: [], onbastion: false}
- { name: "osr1", id: 15009, state: "present", groups: ["project"], onbastion: false }
- { name: "osr2", id: 15010, state: "present", groups: ["project"], onbastion: false }
- { name: "osr3", id: 15011, state: "present", groups: ["project"], onbastion: false }
- { name: "project_svc", id: 15018, state: "present", groups: ["project"], onbastion: false }
- { name: "jenkins", id: 15019, state: "present", groups: ["project"], onbastion: false }
project/roles/create-accounts/tasks/main.yml
- name: Set up user accounts
ansible.builtin.include_tasks: create-account.yml
loop: "{{ users }}"
project/roles/create-accounts/tasks/create-account.yml
---
- name: Update item state if on bastion
set_fact:
desired_item_state: "{{ 'absent' if ('bastion' in group_names and item.onbastion == false) else item.state }}"
- name: Create/update {{ item.name }} user ID
become: true
ansible.builtin.user:
name: "{{ item.name }}"
state: "{{ desired_item_state }}"
uid: "{{ item.id }}"
groups: "{{ item.groups }}"
append: yes
update_password: on_create
password: "!"
- name: Create/update {{ item.name }} group ID
become: true
ansible.builtin.group:
name: "{{ item.name }}"
state: "{{ desired_item_state }}"
gid: "{{ item.id }}"
- name: Update ownership of /home/{{ item.name }}
become: true
ansible.builtin.file:
path: /home/{{ item.name }}
state: directory
recurse: yes
owner: "{{ item.name }}"
group: "{{ item.name }}"
when: desired_item_state == 'present'
Output
TASK [create-accounts : Create/update osr1 user ID] ***********************
fatal: [project-subsystem-bastion2]: FAILED! =>
msg: |-
The task includes an option with an undefined variable. The error was: 'desired_item_state' is undefined
The error appears to be in '/project/ansible-e86f3754/plays/roles/create-accounts/tasks/create-account.yml': line 13, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Create/update {{ item.name }} user ID
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
See comments. flowerysong was unable to reproduce my issue, and the only thing I'd left out were tags on the tasks. Lesson learned: sanitize code before posting but don't leave anything out.

Migrating from angularjs select to selectize empty value

Currently I use angularjs select directive, I have a choice to reset to None value
<select ng-model="myModel" ng-options="selectOptions">
<option value="">None</option>
</select>
When I select the None option myModel is null
{{ myModel === null }} // true
I want to have the same behaviour with angularjs selectize so I am adding an option with "" value.
onInitialize: function(selectize) {
selectize.addOption({id: '', name: 'None'});
}
So when I choose none with selectize my model is an empty string and not null
{{ myModel === null }} // false
How can I change this to null ?
Is it possible to do it without writing a new directive ?
You can assign to id value null, 0 (zero) or let it undefined like this:
onInitialize: function(selectize) {
selectize.addOption({id: null, name: 'None'});
// selectize.addOption({id: 0, name: 'None'});
// selectize.addOption({name: 'None'});
}
and check it like this:
{{ !myModel }}
As an alternate solution you could just check against the '' (empty value) like this:
{{ myModel === '' }}
I have found a way by extending the plugin on
scope.$watch('ngModel', setSelectizeValue);
var setSelectizeValue = function() {
if(scope.ngModel === '') {
scope.ngModel=null;
}
Still looking for a way without extending the plugin.

How to access objects in Jekyll array?

My Jekyll page code is as following (simplified):
_layouts/content.html:
---
layout: null
---
<pre>
{{ content }}
</pre>
any_page.md
---
layout: content
social:
- twitter :
url : "https://twitter.com"
user : "foo"
show : true
- instagram :
url : "https://instagram.com"
user : "bar"
show : false
---
My understanding of above in any_page.md is
social is an array of objects having items 0, 1; social[0] equals to * twitter. These keys can be variable.
each array item in above array is social[i]; an object having similar known keys (url, user, show)
Problem:
How to access page.social[i]["url"] & other two known keys?
How to access these known keys of an object residing in a variable-length array?
How to get the following outputs: twitter, https://twitter.com, foo, true
Code I have tried:
all social array: {{ page.social }} outputs (as expected)
{“twitter”=>
{ “url”=>”https://twitter.com”,
“user”=>”foo”,
“show”=>true
}
}
{“instagram”=>
{ “url”=>”https://instagram.com”,
“user”=>”bar”,
“show”=>false
}
}
social array's first object: {{ page.social[0] }} outputs (as expected)
{“twitter”=>
{ “url”=>”https://twitter.com”,
“user”=>”foo”,
“show”=>true
}
}
Failed attempts to access url of item 01 (all results to empty):
{{ page.social[0]["url"] }}
{{ page.social[0][url] }}
{{ page.social[0]."url" }}
{{ page.social[0].url }}
{{ page.social[0][0] }}
Addendum:
I have also tried the for loop; & it gives all the values on root level (twitter etc..), but no access to the object keys:
{% for item in page.social %}
item = {{ item }} # works
item[URL] = {{ item[url] }} # empty
item["URL"] = {{ item["url"] }} # empty
item."URL" = {{ item."url" }} # empty
item.URL = {{ item.url }} # empty
i = {{forloop.index }} # ok, but starts from 1 instead of 0
{% endfor %}
This will work:
twitter key: {{page.social[0]|first|first}}
<h2>data</h2>
url: {{page.social[0]['twitter'].url}}
user: {{page.social[0]['twitter'].user}}
show: {{page.social[0]['twitter'].show}}
Another approach
social:
twitter :
url : "https://twitter.com"
user : "foo"
show : true
instagram :
url : "https://instagram.com"
user : "bar"
show : false
Then you can access it with:
{% for item in page.social%}
key: {{item[0]}}<br>
{% endfor %}
<hr>
<h2>data</h2>
url: {{page.social['twitter'].url}}
user: {{page.social['twitter'].user}}
show: {{page.social['twitter'].show}}
I have accepted marcanuy's answer, here I am just documenting what I used based on his answer;
{% for item in page.social %} # OUTPUT for 1st item
{{ item[0] }} # twitter:
{{ item[1].url }} # https://twitter.com
{{ item[1].user }} # foo
{{ item[1].show }} # true
{% endfor %}
Also, the declaration in front matter is bit changed. The one which works with above code is:
social:
twitter :
url : "https://twitter.com"
user : "foo"
show : true
instagram :
url : "https://instagram.com"
user : "bar"
show : false
Note the missing - dashes. Although both ways are correct, I need to read more to how to access both.
As mentioned at http://yaml.org/spec/1.2/spec.html, indentations & - matter. Each item having more spaces than earlier makes itself child of earlier.

GroupBy date and time, orderBy date, and time AngularJS

I am trying to achieve this view here. From what I have it works great until an event occurs the next day, then the time order doesn't work, and also the events from next day are displayed after the one occurred previously. I'm using angular.filter to group my results
MyController
$scope.histories = response.revision_history.map(function (data) {
return {
"date": data.created_at.substring(0,10),
"time": data.created_at.substring(11,19),
"user": data.user_id,
"property": data.key,
"old": data.old_value,
"new": data.new_value
}
});
Jade
.col-md-12(ng-repeat="history in histories | groupBy: 'date' | toArray: true")
.crm-history-seperator
span {{ history[0].date }}
.repeater(ng-repeat="event in history | groupBy: 'time' | toArray: true")
span.time {{ event[0].time }}
.repeater(ng-repeat="ev in event")
.content
.activity
span.user {{ ev.user }}
span.explanation Changed {{ ev.property }}
span.explanation(ng-if="ev.old !== null") from
span.event(ng-if="ev.old !== null") {{ ev.old }}
span.explanation to
span.event {{ ev.new }}
Here is what I get if some event happens the next day
Here is what I want to achieve
From what I've concluded, order by is not working in your case. I think your answer lies between the way groupBy and orderBy expects arguments. Have a look at below answer.
https://github.com/a8m/angular-filter/issues/57#issuecomment-65041792

Use angularjs filter with parameters in the json

I want to filter a list and get all the elements which have an argument equals to true. But my argument is a property and I don't know how to tell to angularjs to compute it.
{{ list | filter: {argument: true} }}
For instance if I have scope.argument = 'foo' my html should interpret it like this
{{ list | filter: {'test': true} }}
Is it possible?
I found a solution.
I create a filter in my controller
scope.isSelected = function(element) {
return element[scope.argument] === true;
}
and then I use it in my html like this
{{ (list | filter: isSelected).length }}
I would prefer to do this directly in my html but I didn't find a way to do it.

Resources