Angularjs dynamic ng-if data binding in span - javascript

I have this Angular expression in my view:
<span ng-if="{{list.StoreList ? (list.StoreList.length ' Products)' : '(0 Products)'}}"> </span>
So if I have any items in the StoreList then I'll display the count, otherwise I'll just show 0 products.
I'm getting unexpected expecting error from Angularjs.
How can I solve this?

Try with:
<span ng-if="list.StoreList">{{'(' + list.StoreList.length + ' Products)'}}</span>
<span ng-if="!list.StoreList">(0 Products)</span>

This is not formatted correctly
<span ng-if="{{list.StoreList ? (list.StoreList.length ' Products)' : '(0 Products)'}}"> </span>
should probably be
<span ng-if="{{ list.StoreList ? '(' + list.StoreList.length + ' Products)' : '(0 Products)'}}"> </span>

Related

How to append a string and html tag in ternary operator condition?

I have a ternary condition in React
return <span>
{
data.length > 136
? this.trimStringLength(data, 136) + (<span>see more...</span>)
: data
}
</span>;
Here, this.trimStringLength provides a trim string.
The result should be "some data here see more..." but I am geeting "some data here[object Object]"
How can I concatenate to get the required result?
Use a Fragment:
E.g.:
<span>
{data.length > 136
? <>{this.trimStringLength(data, 136)} <span>see more...</span></>
: data}
</span>
You can use it like this, no need to use the + sign
<span>
{
data.length > 136
?
(<>{this.trimStringLength(data, 136)} <span> see more...</span></>)
:
data
}
</span>
Seems like you are concatenating a string and an object instead of two strings.
Have you tried replacing the span element with a string, like so ?
<span>
{
data.length > 136
?
this.trimStringLength(data, 136) + "see more..."
:
data
}
</span>

How to convert string to expression ( value ) in aurelia repeat for?

Array used in repeat for loop
let loopArr = ["item.name + ' /'+ item.DisplayName? item.DisplayName: item.otherDisplayName",
"item.description + ' /'+ item.anotherDescription"]
Template
<div repeat.for = item of data">
<div repeat.for = "row of loopArr">
<span textcontent.bind="renderRow(row, item)></span>
</div>
</div>
Component method
renderRow(row, item){
return eval(row)
}
Actually I wanted to display like below in template
<div repeat.for = item of data">
<div repeat.for = "row of loopArr">
<span>${item.name + ' /'+ item.DisplayName? item.DisplayName: item.otherDisplayName} </span>
<span>${item.description + ' /'+ item.anotherDescription} </span>
</div>
</div>
Since I wanted to loop through dynamic loopArr, instead of using eval to convert from string to value, is there any better way to compute the value from string? Also, eval doesnt work for multiline statements, is there any other approach/way to handle the above problem?
How to convert string to value and display in aurelia template?
Any help would be appreciated!
I'm not sure why you're adding the logic in string format and using eval. You could directly add it to the template and display it:
<div repeat.for="item of data">
<span>${item.name + '/' + (item.DisplayName ? item.DisplayName: item.otherDisplayName)}</span>
<span>${item.description + ' / '+ item.anotherDescription} </span>
</div>
Let's assume you have a list of custom string formats and you are importing them from another file. You could create an array of functions instead of array of strings. This is much better way of deferring the string creation than running eval
displayTemplates = [
item => item.name + '/' + (item.DisplayName ? item.DisplayName: item.otherDisplayName),
item => item.description + '/'+ item.anotherDescription
]
and then in the template:
<div repeat.for="item of data">
<template repeat.for="func of displayTemplates">
<span>${ func(item) }</span> <!-- call each func on item object -->
</template>
</div>
Also, there is a logical error in your string format. + operator has higher precedence compared to the ternary operator.
So,
item.name + '/' + item.DisplayName ? item.DisplayName : item.otherDisplayName
is actually evaluated as
(item.name + '/' + item.DisplayName) ? item.DisplayName : item.otherDisplayName
So, this expression will always evaluate to item.DisplayName because item.name + '/' + item.DisplayName will never be falsy.
You need to add () around the ternary operation:
item.name + '/' + (item.DisplayName ? item.DisplayName: item.otherDisplayName)
// OR
item.name + '/' + (item.DisplayName ?? item.otherDisplayName)

Use if else at Javascript

I have a section on the site where used items parsing from Steam API. Every item has an attribute market_hash_name, classid, and i have virtual items on the site that don’t have these attributes, that have items from Steam.
The problem is this: items from the Steam service are displayed normally, and virtual items are not displayed, an error appears in the site console VM13384:1 Uncaught SyntaxError: Unexpected token u in JSON at position 0, these json requests have the variables + info.classid + and + info.name +, which my virtual items don't have and therefore are not displayed and I get an error. How i can fix this error?
My JS code:
html_items = '';
json1.forEach(function(info){
html_items += '<li class="fast-game-trade-item" style="transform: translate3d(0px, 0px, 0px); background-image: url(https://steamcommunity-a.akamaihd.net/economy/image/' + info.classid + '/23fx23f);"><div class="item_info darkBlueBg">\
<div class="item_info_img_wrap">\
<div class="item_info_img">\
<img src="https://steamcommunity-a.akamaihd.net/economy/image/' + info.classid + '/110fx100f" alt="' + info.market_hash_name + '">\
</div>\
</div>\
<div class="item_info_description">\
<div class="item_info_name">' + info.market_hash_name + '</div>\
<div class="item_info_price">' + info.price + '₽</div>\
</div>\
<div class="item_owner">\
<div class="item_owner_img">\
<img src="' + data1.user.avatar + '">\
</div>\
</div>\
</div></li>';
});
$('#game_'+data1.game_id+' #block_items_1').html(html_items);
In site templates I solve this problem as follows:
#if(!isset($i->img))
here code for Steam items
#else
here code for virtual items
#endif
How can I use #if #else in my case in Javascript?
EDIT add code with JSON parse:
data1 = JSON.parse(data);
var string = JSON.stringify(data1.items);
var json = JSON.parse(string);
var json1 = JSON.parse(json);
$('#bank').text(data1.gamePrice);
if (data1.number == 1) {
if(window.location.pathname == '/fastgame') {
$('title').text(Math.round(data.gamePrice,2) + '');
}
$('#game_'+data1.game_id+' #chance_1').toggleClass('chance_'+data1.user.id);
$('#game_'+data1.game_id+' #block_1 .player.first-player').css('background-image', 'url(' + data1.user.avatar + ')');
$('#game_'+data1.game_id+' #block_1').removeClass('empty');
$('#game_'+data1.game_id+' #block_1 .players-roulette-container').attr('id','bet_1_'+ data1.betId);
html_items = '';
json1.forEach(function(info){
html_items += '<li class="fast-game-trade-item" style="transform: translate3d(0px, 0px, 0px); background-image: url(https://steamcommunity-a.akamaihd.net/economy/image/' + info.classid + '/23fx23f);"><div class="item_info darkBlueBg">\
<div class="item_info_img_wrap">\
<div class="item_info_img">\
<img src="https://steamcommunity-a.akamaihd.net/economy/image/' + info.classid + '/110fx100f" alt="' + info.market_hash_name + '">\
</div>\
</div>\
<div class="item_info_description">\
<div class="item_info_name">' + info.market_hash_name + '</div>\
<div class="item_info_price">' + info.price + '₽</div>\
</div>\
<div class="item_owner">\
<div class="item_owner_img">\
<img src="' + data1.user.avatar + '">\
</div>\
</div>\
</div></li>';
});
$('#game_'+data1.game_id+' #block_items_1').html(html_items);
$('#game_'+data1.game_id+' #price_1').text(data1.price).countTo({
from: 0,
to: data1.price,
speed: 600,
formatter: function(value, options) {
return value.toFixed(2);
}
});
}
Solution to issue "JSON parsing error"
The reason you are getting Uncaught SyntaxError: Unexpected token u in JSON at position 0 is that you are somewhere stuffing undefined into JSON.parse. This is because JSON.parse will convert whatever you passed into it to a string and attempt to parse it, but undefined is not valid JSON, and you are getting an error at the first character already, which is u.
I don't see JSON.parse in your code, so this error must happen in a place you did not copy here.
Everything I'm going to explain below is not going to work unless you fix this error first. So please check where you are parsing your JSON and don't attempt to parse it if the text you are parsing is undefined.
A tip on the side: Open your browser console before the error happens (or refresh the page if you opened it too late). Then you will get more useful error output and most importantly also better info about where the error happened, especially when you have source maps. Even better, you will usually break into the code at the moment the error happens, so you can inspect the variables and see for example why you had undefined there. Also, when you click that file and line number at the right (VM13384:1 in your case), it will show you the line of code where it happened. If the code is minified (which I assume since here it shows line 1), you can click the {} button to auto-format it.
Answer to question "how to embed conditionals in a string"
You can use the ternary conditional operator ?:.
The syntax is condition ? valueIfTrue : valueIfFalse, and it evaluates to valueIfTrue when condition was truthy, otherwise it evaluates to valueIfFalse.
For example:
console.log('Is one greater than two? ' + (1 > 2 ? 'Yes' : 'No') + '!')
// Output: Is one greater than two? No!
Further notes
On a side note, the code will become much neater by using template strings (they use `backticks` and you can embed ${values} in them, and they can contain newlines):
html_items += `
<li class="fast-game-trade-item" style="transform: translate3d(0px, 0px, 0px); background-image: url(https://steamcommunity-a.akamaihd.net/economy/image/${info.classId}/23fx23f);"><div class="item_info darkBlueBg">
<div class="item_info_img_wrap">
<div class="item_info_img">
<img src="https://steamcommunity-a.akamaihd.net/economy/image/${info.classId}/110fx100f" alt="' + info.market_hash_name + '">
</div>
</div>
<div class="item_info_description">
<div class="item_info_name">${info.market_hash_name}</div>
<div class="item_info_price">${info.price}₽</div>
</div>
<div class="item_owner">
<div class="item_owner_img">
<img src="${data1.user.avatar}">
</div>
</div>
</li>
`;
Of course you could nest them, together with conditionals:
`
<div class="list">
${items.length > 0 ? `
<ul>
${items.map(item => `
<li>${item}</li>
`).join('')}
</ul>
`, `
<strong>No items!</strong>
`}
</div>
`
However, with all of this, there is still one issue: You are not escaping your text as HTML entities, so that HTML can sneak in, which can break formatting at best or cause XSS attack vulnerabilities at worst.
You should wrap all the text values in an escaping function. Unfortunately, browsers still don't have a straight-forward function to do that, but it's easy to create one yourself:
function esc (s) {
const i = document.createElement('i')
i.innerText = s
return i.innerHTML
}
This way, you can escape your text values like so:
`
<div class="item_info_name">${esc(info.market_hash_name)}</div>
`

How to display dynamic HTML in uib-popover inject into uib-grid

I want to display a dynamic generated HTML in uib-popover, and it's shown when a <i> is clicked in each column header of uib-grid. The ng directives and variables also need to be active, such as ng-click, $scope etc.
I tried to use the headerCellTemplate in each column definition of uib-grid for displaying the<i>tag, and I passed a dynamic generated HtML to each column definition, so that I can get it in the headerCellTemplate with col.displayName.popoverTemplate, It works fine. But I can't pass any variables in to popover use $scope, and ng-click don't work at all. Someone said I need to compile the HTML or use the uib-popover-template, how do I pass params to uib-popover-html or there is another way.
THANKS!
columnDefs
columnDefs.push({
name:'columnViewData._name',
displayName:{//use this file to pass params into uib-grid headers
displayName:'columnName',
popoverTemplate:generatePopoverTemplate(),//template should be shown in popover for this column header
customerScope:$scope//current scope, I hope popover can access it
},
width:100,
enableColumnMenu:false,
pinnedLeft:true,
headerCellTemplate:generateUIGridHeaderTemplate('name',0)
});
Column header template:
var generateUIGridHeaderTemplate = function(columnName,type){
return "\
<div role=\"columnheader\" ng-class=\"{ 'sortable': sortable }\" ui-grid-one-bind-aria-labelledby-grid=\"col.uid + '-header-text ' + col.uid + '-sortdir-text'\" aria-sort=\"{{col.sort.direction == asc ? 'ascending' : ( col.sort.direction == desc ? 'descending' : (!col.sort.direction ? 'none' : 'other'))}}\">\
<div style=\"margin-top:0.3em;\">\
<div style=\"display:inline;\" role=\"button\" tabindex=\"0\" class=\"ui-grid-cell-contents ui-grid-header-cell-primary-focus\" col-index=\"renderIndex\" title=\"TOOLTIP\">\
<span class=\"ui-grid-header-cell-label\" ui-grid-one-bind-id-grid=\"col.uid + '-header-text'\">\
{{ col.displayName.displayName CUSTOM_FILTERS }}\
</span> \
<span ui-grid-one-bind-id-grid=\"col.uid + '-sortdir-text'\" ui-grid-visible=\"col.sort.direction\" aria-label=\"{{getSortDirectionAriaLabel()}}\">\
<i ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\" title=\"{{isSortPriorityVisible() ? i18n.headerCell.priority + ' ' + ( col.sort.priority + 1 ) : null}}\" aria-hidden=\"true\">\
</i> \
<sub ui-grid-visible=\"isSortPriorityVisible()\" class=\"ui-grid-sort-priority-number\">\
{{col.sort.priority + 1}}\
</sub>\
</span>\
</div>\
<i style=\"margin-left:-1em;\" class=\"glyphicon glyphicon-filter\" popover-placement='bottom' uib-popover-html=\"col.displayName.popoverTemplate\" popover-title=\"Filter\" popover-append-to-body=\"true\">\
</i>\
<!-- above line is the popover togger shown in the column header-->\
</div>\
<div role=\"button\" tabindex=\"0\" ui-grid-one-bind-id-grid=\"col.uid + '-menu-button'\" class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-class=\"{'ui-grid-column-menu-button-last-col': isLastCol}\" ui-grid-one-bind-aria-label=\"i18n.headerCell.aria.columnMenuButtonLabel\" aria-haspopup=\"true\">\
<i class=\"ui-grid-icon-angle-down\" aria-hidden=\"true\">\
\
</i>\
</div>\
<div ui-grid-filter>\
</div>\
</div>"}
Popover template
var generatePopoverTemplate = function(){
var t = $sce.trustAsHtml('<a class="btn" ng-click="alert(\'asd\')">asd</a>');
$compile(t)($scope);
return t;
}
I solved my question :)
Generate the popover template and put it in to $compileCache with an Id then uib-popover-template property can find it and ng works fine.

AngularJS - HTML data binding UI issue

I am binding following in my HTML.
<div>{{user.address[0].addressline1}}, {{user.address[0].addressline2}}, {{user.address[0].city}}, {{user.address[0].state}}, {{user.address[0].zipcode}}</div>
The issue is if addressline1 is null, it unnecessarily shows the , at first.
And also some other fields can be null
So How to display comma only if the value is not null?
Or as a matter of style, you can use a turnery operator to check for the value then format it
{{ !!user.address[0].addressline1 ? user.address[0].addressline1 + ', ' : ''}}
This could be made as filter to be more intuitive
angular.module('myapp', []).filter('trailIfTrue', [function(){
return function(val, trail){
return !!val ? val + trail : '';
}
}]);
usage:
{{ user.address[0].addressline1 | trailIfTrue:',' }}
here is a plunker
User separate span and ng-show so the span will be shown only if user.address[0].addressline1 is not null
<span ng-show="user.address[0].addressline1">{{user.address[0].addressline1}},</span>
<span ng-show="user.address[0].addressline2">{{user.address[0]. addressline2}},</span>
<span ng-show="user.address[0].city">{{user.address[0].city}},</span>
//...
You can use any expression into ng-show Eg:
user.address[0].addressline1 != null
myObj.myIntAttr > 0 && < 10
myObj.myBoolAttr == false
//...

Categories

Resources