How to assign local variable in Jquery template - javascript

Below, I am trying to print replaced items using Jquery template. There I want to set a variable partHasBeenReplaced which later I can use to print the label and close the <span> element.
How can I set variable there?
How to find the last element of type "REPLACEMENT"? it may not be the last element of the array.
{{each(i,ref) productReferences}}
{{if ref.referenceType == 'REPLACEMENT'}}
{{partHasBeenReplaced = 'true'}}
{{/if}}
{{/each}}
{{if partHasBeenReplaced == 'true'}}
<span class="text-danger font-weight-bold pt-2">
This item has been replaced with:
{{/if}}
{{each(i,ref) productReferences}}
{{if ref.referenceType == 'REPLACEMENT'}}
{{= ref.target.code}} ,
{{/if}}
{{/each}}
{{if partHasBeenReplaced == 'true'}}
</span>
{{/if}}

In order to assign data to an element using such templates, it better to use attributes. We can access create/update/remove attribute using JavaScript.
For an example, if you want to add a data for <span> then you can do it using -
<span id="mySpan" class="text-danger font-weight-bold pt-2" partreplaced="{{partHasBeenReplaced}}" ></span>
It can be accessed in JavaScript using below method -
let span = document.querySelector("#mySpan");
let partreplaced = span.getAttribute('partreplaced');
console.log(partreplaced); //will print which was set in that attribute using the templating engine.

There is no simple solution to set the local variable as we do in JSTL. So what I did is I have used JS to populate final flag like partHasBeenReplaced and set it to data before passing it to Jquery template. So that I can directly use the variable in the template.

Related

How to do string interpolation in template element in Vue.js?

I am iterating through a dictionary (called in from a .json file) and would like to check an attribute of my props with a value in the dictionary. In my first div I am setting the variable attribute to be one of the values in the dictionary. This attribute variable has the value "event" which is exactly what I want.
In the inner div, the props.item.${attribute} code is not evaluating to props.item.event, which is what I thought it would. Is there any way to interpolate the value of this variable to my props statement?
<div
v-for="data in dict"
:set="attribute = data.targetAttr"
>
<div v-if="props.item.attribute == data.key">
<a
:href="data.response"
target="_blank"
>
More Info
</a>
</div>
</div>
I have tried looking at the resource here, but the answer is only in relation to effectively mapping over lists, which is not exactly my problem.
VueJs - How to use variable in v-if?
In that case, you should try the following
<div v-if="props.item[attribute] === data.key">

How to render either a number or a HTML element depending on what a function returns?

I have a function getGameScore() which either returns a number or null. Then I call it inside my html file like this:
<span>{{ getGameScore(game) }}</span>
Now I want to change it so that I render the number if a number is returned, or render an icon if it returns null. I tried something like this, but it just returns a string instead of an actual HTML element:
<span>{{ getGameScore(game) ? getGameScore(game) : '<i class="icon ion-checkmark"></i>' }}</span>
How would I render an actual HTML element in that case?
One way would be to use ngIf
For AngularJS:
ng-if
<span ng-If="assessmentRequestValue">{{ assessmentRequestValue }}</span>
<span ng-If="!assessmentRequestValue"><i class="icon ion-checkmark"></i></span>
For Angular2+
NgIf
<span *ngIf="assessmentRequestValue">{{ assessmentRequestValue }}</span>
<span *ngIf="!assessmentRequestValue"><i class="icon ion-checkmark"></i></span>
For both, Try not to use function calls in angular template expressions Use getScore(assessmentRequest) somewhere inside your controller to set assessmentRequestValue
How about using ng-bind-html directive. As stated in original docs
Evaluates the expression and inserts the resulting HTML into the element in a secure way
EG
<span ng-bind-html="getScore(assessmentRequest) ? getScore(assessmentRequest) : '<i class="icon ion-checkmark"></i>' "></span>

Slot: access scope variables

As a simplified example suppose you have this in a component called "my-buttons":
<button v-for='item in items' v-on:click="this.$emit('activate', item)">
<slot>{{ item.name }}</slot>
</button>
If I use the component somewhere else, is there any way to override the slot and access the item.name value? For example:
<my-component items="myItems">
<span class="myspecialstuff">{{ item.name }}</span>
</my-component>
Obviously as it stands now, vue will complain that it can not find item in the scope.
UPDATE2:
the following code does not work due to https://github.com/vuejs/vue/issues/2511. I can't think of anything else. sorry.
UPDATE:
To achieve specific slot overriding, define slots as
<button v-for='item in items' v-on:click="this.$emit('activate', item)">
<slot v-bind:name="'item-'+item.name">{{ item.name }}</slot>
</button>
and override as
<my-component items="myItems">
//you have access to items so you can do this
//specialItems is an array of items which are to be overriden
<span class="myspecialstuff" v-for="item in specialItems" v-bind:slot="'item-'+item.name" >
{{ item.name }}
</span>
</my-component>
Original answer:
that will be very convoluted imho.
there are 2 ways to achieve what you want depending on where <my-component is getting items.
items is passed to my-component as props. (most common case). In that case, you already have access to items and do not need to jump through hoops for it.
<my-component> is getting items through some external sources like a form or api.(less likely) in this case, you can either raise events to pass data or use 2-way bindings through .sync

Pass spacebar parameter to another spacebar parameter

Im trying to pass a parameter from one template to other in meteor.js
i want to do this for DRY sake
The first template looks like this
template(name="myPage")
h3.uppercase.amarillo-hogar
+editaMl(data=this collection="categorias" field="titulo")
template(name="editaMl")
if i18n_isCurrentLanguage 'es'
| {{collection}} {{field}}
+editableText(context=data collection=collection field=field userCanEdit=userCanEdit acceptEmpty=true substitute='<i class="fa fa-pencil"></i>')
else
+editableText(collection=collection field=field userCanEdit=userCanEdit acceptEmpty=true substitute='<i class="fa fa-pencil"></i>')
this is so i can stop repeating myself with every translation field
but cant work around passing a parameter value to another template parameter value
i use jade, now in html for those who do not like jade
<template name="myPage">
<h3 class="uppercase amarillo-hogar>{{> editaMl collection="categorias" field="titulo"}}</h3>
</template
<template name="editaMl">
{{#if i18n_isCurrentLanguage 'es'}}
{{> editableText collection=collection field=field }}
{{/if}}
{{#else}}
{{> editableText collection=collection field=field }}
{{/else}}
</template>
just if you want to know, im using babraham editable text package and tap_i18n with tap_i18n ui for translating
Cant find the reason my helper returns an object when used like this in the content {{collection}} but when used as parameter in the child template does nothing
Code updated and SOLVED
You can use:
Template.registerHelper('yourHelperName', function() {
// your helper
});
It creates a helper available in all templates.

define a variable inside a jsrender template

I need to keep a "colcounter" variable inside the loop that will be used to fill a jsrender template.
Here is my template code
<script id="datascapeTemplate" type="text/x-jsrender">
<div id="dsViewport">
<div class="ds-column" style="width:{{:(name.length*100)}}px;">
<h1 id="datascapeName">{{:name}}</h1>
<div><span id="dsToggle">toggle</span></div>
</div>
{{=colcounter}}
{{for sections}}
<div class="ds-section">
<h3>{{:label}}</h3>
<div class="ds-column" id="start">
{{for items}}
{{* if (colcounter > 4){
colcounter = 1;
}}
</div>
<div class="ds-column" id="start">
{{* } }}
{{*
if ( data.selected || datascape.showInvisible) { }}
<div class="ds-item {{* if (data.featured){ }} nowActive {{*} }} {{* if (data.active){ }} nowActiveRed {{*} }}" background="{{:background}}" bgcolor="#000000" fgcolor="#FFFFFF">
<div class="ds-item-container">
<h4>{{:title}}<br/>{{:time}}</h4>
<p><a item="{{:id}}" href="{{:url}}" class="itemLink">view file {{:colcounter}}</a></p>
</div>
</div>
{{* colcounter++; }}
{{* } }}
{{/for}}
</div>
{{* colcounter=1; }}
</div>
{{/for}}
{{* colcounter=1; }}
</div>
</script>
Unfortunately, it prints, on the very first iteration of the loop "Error: colcounter is not defined.". Afterwards it works.
It seems the way i initialise my colcounter variable is not working but i fail to find the correct way. var colcounter =0 does not work.
UPDATE
jsfiddle: http://jsfiddle.net/ZX6Mk/
colcounter works now. I declared it in the global scope. But I have an issue with datascape.showInvisible. It also triggers the error
Error: Cannot read property 'showInvisible' of undefined.
Thank you for your time,
a.
I took your fiddle and made a few changes. http://jsfiddle.net/johnpapa/bLSkz/
The toggleButton was being referred to in jQuery without the #. So I added that.List item, otherwise the click was not being captured.
Your fiddle did not reference jQuery nor JsRender, though you were using both, so I added them. (I assume you never ran the fiddle)
There was no datascape.showInvisible property, so I created one.
I passed showInvisible to the inner for loop using a parameter, so it could be accessed in its context.
{{for sections ~showIt=showInvisible}}
{{if (editorspick_amount > 0 || ~showIt)}}
The template you were trying to render did not exist, so I changed the rendering code to use the script tag you created. This also sets the allowCode=true, which is required to safely turn on the allowCode feature.
$.templates("myTmpl", {markup: "#datascapeTemplate", allowCode: true });
$('#toggleButton').click(function(){
if(!rendered){
rendered = true;
$("#datascape").html(
$.render.myTmpl( datascape.json )
).show();
}
});
I changed one place where you used {{* }} to instead use an {{if}} block since there was no need to use allow code.
This allowed all of the code to run and the template to render, though I admittedly did not follow all of what you were trying to do.
Hope this helps.
One suggestion ... the allowCode feature makes for really ugly templates and hard to maintain and read. I highly recommend replacing it with helper functions (or other constructs). For example, you used allowCode to create the styling for some elements. You could have used a custom tag for this instead, and moved the logic to javascript and simplified your template. The colcounter could be moved to a helper function. It's just much more readable to move the logic to javascript, and keep the template/html clean. Just my 2 cents :)

Categories

Resources