I am using KnockoutJS which uses a json string within the data-bind attribute to indicate binding information. I also like using HAML.
This string can quickly become quite long, for example:-
%ul#task-list.unstyled{"data-bind" => "template: { name : 'taskHierarchy', foreach : contexts.children(), afterAdd: function(elem) { $(elem).hide().slideDown() } }"}
A solution is to use the :plain filter as follows (slightly different from above):-
:plain
<div data-bind = "template: {
name: 'twoLineResourceTemplate',
foreach: resources,
afterAdd: function(elem) { $(elem).hide().slideDown() }
}">
</div>
Is there a neater way to do this using HAML constructs instead of the filter?
I have tried using the pipe character but it does not seem to work for HAML attributes.
Thanks!
I tried the pipe notation and it works for me:
%ul#task-list.unstyled{"data-bind" => |
"template: { " + |
"name : 'taskHierarchy'," + |
"foreach : contexts.children()," + |
"afterAdd: function(elem) {" + |
"$(elem).hide().slideDown()" + |
"} }"} |
You could try this post on KnockoutJS and Unobtrusive JavaScript
Related
I have the following input and I want to below output using jq.
I would like to add
an entry "zeiterfassungAktiviert" : truejust after the key gueltigBis (or alternatively before the key inhaltsverzeichnis)
add an entry to the end of the object inhaltsverzeichnis by adding the entry "zeiterfassung": "zeiterfassung"
Example input:
{
"fachbereich": "qp",
"produktTyp": "PRODUKT_ANFRAGE_V1",
"name": "Produkt Anfrage",
"kurzName": "anfrage",
"gueltigAb": "2019-01-01T00:00:00.000",
"gueltigBis": "2022-12-31T00:00:00.000",
"inhaltsverzeichnis": {
"versandumfang": "auftragsverwaltung/versandumfang",
"dokumentenerzeugung": "dokumentenerzeugung"
}
}
Example output:
{
"fachbereich": "qp",
"produktTyp": "PRODUKT_ANFRAGE_V1",
"name": "Produkt Anfrage",
"kurzName": "anfrage",
"gueltigAb": "2019-01-01T00:00:00.000",
"gueltigBis": "2022-12-31T00:00:00.000",
"zeiterfassungAktiviert": true,
"inhaltsverzeichnis": {
"versandumfang": "auftragsverwaltung/versandumfang",
"dokumentenerzeugung": "dokumentenerzeugung",
"zeiterfassung": "zeiterfassung"
},
}
I managed to do the second part but am not clear about how to go about the first part.
Command: jq '.zeiterfassungAktiviert += "zeiterfassung" | .inhaltsverzeichnis.zeiterfassung += "zeiterfassung"'
The result is as follows:
{
"fachbereich": "qp",
"produktTyp": "PRODUKT_ANFRAGE_V1",
"name": "Produkt Anfrage",
"kurzName": "anfrage",
"gueltigAb": "2019-01-01T00:00:00.000",
"gueltigBis": "2022-12-31T00:00:00.000",
"inhaltsverzeichnis": {
"versandumfang": "auftragsverwaltung/versandumfang",
"dokumentenerzeugung": "dokumentenerzeugung",
"zeiterfassung": "zeiterfassung"
},
"zeiterfassungAktiviert": true
}
As you can see it is added to the end of the root object. I would like to specify the position somehow, ideally without having to convert into array and convert back if possible but rather by saying please add entry after/before a specified key.
For the first part, it helps to have a helper function:
def insertkv($afterkey; $key; $value):
def insertafter($ix; $x): .[0:1+$ix] + [$x] + .[1+$ix:];
to_entries
| insertafter( map(.key) | index($afterkey); {$key, $value})
| from_entries;
Versions
The above is intended for use with jq 1.5 or later. Some minor fiddling is required for earlier versions.
I have this ternary operator in my html (working correctly)
{{ qp.QP_TRANSFERS === '1' ? qp.QP_TRANSFER_TYPE_NAME + ' transfer' : 'No transfer' }}
I'm using translation service from json objects. This is an example of en_US.json file:
"myquotes": {
"PAGETITLE": "My quotes",
"DESCRIPTION": "List of all your asked quotes",
"packages": {
"label": {
"SEARCH": {
"TITLE": "Package quotes",
"DESCRIPTION": "Search by any column",
"QUOTE": "Quote",
"ADULTS": "Adults",
"MINORS": "Minors",
"TRANSFER": "transfer",
"NOTRANSFER": "No transfer"
}
},
}
}
And I use it like this:
{{ 'myquotes.packages.label.ADULTS' | translate }}
Is there a way to use this service in my ternary example?
In this plunker you have a working example of what I understand you are looking for.
You basically you have use parenthesis to wrap your ternary expression ( ... ) before you use the translate filter, but I recommend you to put that logic inside a function on your controller to have a more readable template:
<p>{{ ('myquotes.packages.label.SEARCH.' + (qp.QP_TRANSFERS === '1' ? 'TRANSFER' : 'NOTRANSFER')) | translate}}</p>
Or:
<p>{{ getLabel(qp.QP_TRANSFERS) | translate}}</p>
Other option could be to use the ng-init directive to initilize the full string Key once into a variable and then use the translatefilter against that variable, something like this:
<p
ng-init="LABEL = 'myquotes.packages.label.SEARCH.' +
(qp.QP_TRANSFERS === '1' ? 'TRANSFER' : 'NOTRANSFER')">
{{ LABEL | translate}}
</p>
I'd like to replace the tokens in text with the variables defined in ma. Input JSON:
{
"ma":{
"a":"1",
"b":"2",
"c":"3"
},
"mb":{
"a":"11"
},
"text":"https://ph.com?a={a}&b={b}"
}
Desired result: https://ph.com?a=1&b=2
Extra credit, how can I have mb variables take precedence over ma variables so that my resulting text is: https://ph.com?a=11&b=2 ?
I've tried using combinations of scan and sub and walk but can't figure it out.
Thanks!
Define a function to replace the tokens with the new values.
def format($map): gsub("\\{(?<key>[^}]+)\\}"; "\($map[.key])");
With this, you can then pass in the map for the replacements.
.ma as $map | .text | format($map)
Update the mapping as needed.
(.ma * .mb) as $map | .text | format($map)
If you're stuck with the {a}-style template names, then see #JeffMercado's answer; if, however, you have control over the templating style, it would make things much simpler if you used jq's string-interpolation feature.
For example, if the template string (.text) were "https://ph.com?a=\\(.a)&b=\\(.b)" then if you just want the value of .text after substitution, you could simply write:
(.ma + .mb) as $map | .text | $map
Or if you wanted in-place substitution:
(.ma + .mb) as $map
| .text |= $map
I need to show the number of keys in a json object on a web page. So, is there a way to calculate the count directly in the angular expression?
For example,
JSON:
$scope.json = {"key1": "value1", "key2": "value2", key3: "value3"}
For this 'json', there are three keys. I want to get the count of keys directly in an angular expression without calculating it in the controller.
You would have to use a custom filter like this:
template:
{{json | numKeys}}
filter:
app.filter('numKeys', function() {
return function(json) {
var keys = Object.keys(json)
return keys.length;
}
})
Some hacky way would be to do the following:
howManyKeys = {
a: 'Do',
b: 'I',
c: 'have?',
}
If you only want to use it a few times:
This object has {{ (howManyKeys | keyValue).length }} keys
<span *ngIf="(howManyKeys | keyValue).length > 2">That's more than 2!</span>
If you only want to show it on many spots:
<span *ngFor="let howManyKeysLength of [(howManyKeys | keyValue).length]">
This object has {{howManyKeysLength}} keys.
<span *ngIf="howManyKeysLength > 2">That's more than 2!</span>
<span *ngIf="howManyKeysLength < 5">Less than 5!</span>
</span>
This can be useful when you don't want to add a service.
type="checkbox" name="prdCdList" value="102001174" class="bnone" newfl="Y" cpnfl="N" catcpnfl="N" eventfl="N" catcd1="102000" catcd2="102001" prdimgl="/upload/product/320_1405497216907.jpg" prdnm="Dear my volume" prdvol="3.4g" prdlndesc="Limited Pink" selprc="10000" spsalprc="0" cpnprc="0" cashptrat="0" cashpt="0" discpt="0" salstatcdnm="Available" salstatcd="PS01" prdwidth="0" prdheight="0" prddepth="0" pricestr="" price="10000" prepromote="" endpromote=""
I am currently using bunch of regexes to parse above data into a structured array or hash.
Actual tag includes much more values. Thought there must be a better way in Ruby like using split or something? There are spaces between attributes but also within certain values so..
Can any one suggest a good way to handle this type of string?
I would like the result be:
hash = {
type => "checkbox",
name => "prdCdList",
... so on.
}
or
arr = [
"checkbox",
"prdCdList",
... so on.
]
Would appreciate any advice =]
Thanks,
node.attributes.each_with_object({}) {|(k,v), acc| acc[k] = v.value }
where node is your tag.
Using Nokogiri, the attributes are already parsed for you - simply access them using []:
doc = Nokogiri::HTML.parse('<html><body><div type="checkbox" name="prdCdList" value="102001174" class="bnone" newfl="Y" cpnfl="N" catcpnfl="N" eventfl="N" catcd1="102000" catcd2="102001" prdimgl="/upload/product/320_1405497216907.jpg" prdnm="Dear my volume" prdvol="3.4g" prdlndesc="Limited Pink" selprc="10000" spsalprc="0" cpnprc="0" cashptrat="0" cashpt="0" discpt="0" salstatcdnm="Available" salstatcd="PS01" prdwidth="0" prdheight="0" prddepth="0" pricestr="" price="10000" prepromote="" endpromote=""></body></html>')
div = doc.css('div').first
div['prdnm']
# => "Dear my volume"
From the documentation:
Nokogiri::XML::Node is your window to the fun filled world of dealing
with XML and HTML tags. A Nokogiri::XML::Node may be treated similarly
to a hash with regard to attributes. For example (from irb):
01.irb(main):004:0> node
02.=> link
03.irb(main):005:0> node['href']
04.=> "#foo"
05.irb(main):006:0> node.keys
06.=> ["href", "id"]
07.irb(main):007:0> node.values
08.=> ["#foo", "link"]
09.irb(main):008:0> node['class'] = 'green'
10.=> "green"
11.irb(main):009:0> node
12.=> link
13.irb(main):010:0>
See Nokogiri::XML::Node#[] and Nokogiri::XML#[]= for more information.