How do I prevent <span> element from getting created if certain property in $root is null? - razor

I display some text in a <span> element which looks like this
<span data-bind="text: $root.participants()[_propkey].Currency"></span>
When root.participants()[_propkey].Currency is null, I get an empty space on page.
How do I prevent this span from getting created if root.participants()[_propkey].Currency is null

you can use virtual elements and the if binding to achieve what you're after
var vm = {
Currency : ko.observable()
};
ko.applyBindings(vm);
span {background-color: cornflowerblue}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
Currency span
<!-- ko if: Currency -->
<span data-bind="text: Currency"></span>
<!-- /ko -->
is here
<br />
Test: <input data-bind="textInput: Currency">

Related

How can I fix input width and label spacing to match surrounding lightning inputs

I have a LWC, there is a section which comprises of filters. Most of them are standard lightning-inputs, but two of them, are custom lookup components. The problem is, I can't find a way to make them align and look the same.. even if internally it is applying slds css classes (to some extent). This is how it's looking right now:
As you can see, every lightning input is aligned correctly, but then the two lookup component's inputs are wider and with less space between the label and the input.
This is the lookup html code:
<template>
<label if:true={label} class={getLabelClass} for="combobox">
<abbr if:true={required} title="required" class="slds-required">*</abbr>
{label}
</label>
<div class={getContainerClass}>
<div class={getDropdownClass} aria-expanded={hasResults} aria-haspopup="listbox" role="combobox">
<!-- Search input start -->
<div class={getComboboxClass} role="none">
<!-- Text input -->
<template if:false={useInput}>
<slot
aria-autocomplete="list"
aria-controls="listbox"
role="textbox"
id="combobox"
onchange={handleInput}
oninput={handleInput}
onkeydown={handleKeyDown}
onslotchange={handleSlotChange}
></slot>
</template>
<template if:true={useInput}>
<input onfocus={handleFocus}
onblur={handleBlur}
oninput={handleInput}
class="slds-input"
style="color: black;"/>
</template>
<template if:true={isLookup}>
<!-- Search icon -->
<lightning-icon
icon-name="utility:search"
size="x-small"
alternative-text="Search icon"
class={getSearchIconClass}
></lightning-icon>
<button
title="Remove selected option"
type="button"
onclick={handleClearSelection}
class={getClearSelectionButtonClass}
disabled={disabled}
>
<lightning-icon
icon-name="utility:close"
size="x-small"
alternative-text="Remove selected option"
class="slds-button__icon"
></lightning-icon>
</button>
</template>
</div>
<!-- Search input end -->
<!-- Result list box start -->
<div
id="listbox"
role="listbox"
>
<ul class={getListboxClass} role="presentation">
<!-- Spinner to display when waiting for results of search -->
<div if:true={loading}>
<lightning-spinner variant="brand" alternative-text="Loading" size="small"></lightning-spinner>
</div>
<template for:each={_searchResults} for:item="result">
<li data-id={result.id} onmousedown={handleResultClick} class="slds-listbox__item" key={result.id} role="presentation">
<div class="slds-media slds-listbox__option slds-listbox__option_plain slds-media_small" role="option">
<c-lookup-result template={_template} result={result}></c-lookup-result>
</div>
</li>
</template>
<!-- Result list end -->
<!-- No results start -->
<template if:false={hasResults}>
<li role="presentation">
<span class="slds-media slds-listbox__option_entity" role="option">
<span if:false={loading} class="slds-media__body">No results.</span>
<span if:true={loading} class="slds-media__body">Loading...</span>
</span>
</li>
</template>
<!-- No results end -->
</ul>
</div>
<!-- Result list box end -->
</div>
</div>
</template>
In my case, "useInput" is true
These are the getters:
get getContainerClass() {
let css = 'slds-combobox_container'; // slds-has-inline-listbox // sacado porque moleasta
if (this._hasFocus && this.hasResults) {
css += 'slds-has-input-focus ';
}
if (this.errors.length > 0) {
css += 'has-custom-error';
}
return css;
}
get getDropdownClass() {
let css = 'slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click ';
if (this._hasFocus && (this._currentConfig || this.loading)) {
css += 'slds-is-open';
}
return css;
}
get getComboboxClass() {
let css = 'slds-combobox__form-element slds-input-has-icon ';
return css += this.hasSelection() ? 'slds-input-has-icon_left-right' : 'slds-input-has-icon_right';
}
get getListboxClass() {
return (
'slds-listbox slds-listbox_vertical slds-dropdown slds-dropdown_fluid ' +
(this.scrollAfterNItems ? 'slds-dropdown_length-with-icon-' + this.scrollAfterNItems : '')
);
}
get getClearSelectionButtonClass() {
return (
'slds-button slds-button_icon slds-input__icon slds-input__icon_left ' +
(this.hasSelection() ? '' : 'slds-hide')
);
}
get getSearchIconClass() {
let css = 'slds-input__icon slds-input__icon_right ';
if (!this.isMultiEntry) {
css += this.hasSelection() ? 'slds-hide' : '';
}
return css;
}
get getLabelClass() {
return this.variant === VARIANT_LABEL_HIDDEN
? 'slds-form-element__label slds-assistive-text'
: 'slds-form-element__label';
}
get input() {
return this._input;
}
This is my code for what's on the image:
<template if:true={filters}>
<div class="slds-grid slds-gutters">
<div class="slds-col slds-size_1-of-2">
<c-lwc-filter filter={filters.Nombre} input-variant="label-inline"></c-lwc-filter>
<c-lwc-filter filter={filters.Codigo} input-variant="label-inline"></c-lwc-filter>
<c-lwc-filter filter={filters.CodigoFabricante} input-variant="label-inline"></c-lwc-filter>
</div>
<div class="slds-col slds-size_1-of-2">
<c-lwc-filter filter={filters.CodigoBarra} input-variant="label-inline"></c-lwc-filter>
<div class="slds-form-element slds-form-element_horizontal">
<c-lookup label="Familia" is-lookup=true use-input=true configs={configsFamilia} onremoveselection={removeSelection} data-name="_familiaId"></c-lookup>
</div>
<div class="slds-form-element slds-form-element_horizontal">
<c-lookup label="Marca" is-lookup=true use-input=true configs={configsMarca} onremoveselection={removeSelection} data-name="_marcaId"></c-lookup>
</div>
<c-lwc-filter filter={filters.Modelo} input-variant="label-inline"></c-lwc-filter>
</div>
</div>
</template>
(the lwcFilter components are lightning-inputs internally)
I got the label to be inline, wrapping my custom lookup lwc inside a div with slds-form-element_horizontal class. But the problem is, as the "input" inside the lookup is not just a normal input, it is wider and as I said before, the spacing between the label and said input is very small.
How can I make them look the same as the base lightning-inputs? And for it to work on every screen size? (because I tried using margin or padding but it doesn't look the same with smaller / bigger screens)
Any help would be appreciated!
Have you tried to include slds-form-element__control in getContainerClass()?
Something like this:
get getContainerClass() {
let css = 'slds-combobox_container slds-form-element__control'; // slds-has-inline-listbox // sacado porque moleasta
// ... rest of logic
return css;
}
Does it break anything?

knockoutjs if statement and replace text with html

what would be the best way to aproach this in knockoutjs?
I want to replace the data-bind="text: Order" with an image based on what is returned. Examples of what ive tried are in the code below. First example works ok but just returns text (ASC or DESC). 2nd example just returns both. Third example works but I need to display the object as html. Thanks.
<div class="col-md-3 sort-order">
<!--<div class="col-md-3 sort-field" data-bind="text: Order"></div>-->
<!-- ko if: Order() === 'ASC' -->
<object data='~/Content/svg/plans/order-down.svg' type='image/svg+xml' />
<!-- /ko -->
<!-- ko if: Order() === 'DESC' -->
<object data='~/Content/svg/plans/order-up.svg' type='image/svg+xml' />
<!-- /ko -->
</div>
<!--<div class="col-md-3 sort-order" data-bind="text: (ko.unwrap(Order) == 'ASC') ?'<object data='~/Content/svg/plans/order-down.svg' type='image/svg+xml' />' : '<object data='~/Content/svg/plans/order-up.svg' type='image/svg+xml' />'">
</div>-->
In your code instead of using the text binding use like this:
data-bind="html:'your html part goes here'"

Inserting HTML content into a Vue Tooltip

I'm trying to render a tooltip for a table cell in Vue, for when the table cell's content exceeds 22 characters.
I need to use the v-tooltip library (https://www.npmjs.com/package/v-tooltip)
I can set the content of the tooltip to a simple string correctly using the 'content' attribute, however, when I try to set the html content, the tooltip is blank, and the html content which was supposed to appear inside the tooltip, appears constantly in the td.
<td v-if="cellContent !== null && cellContent.length>22">
<div>
<!-- <span v-tooltip.right="{content: 'This works, but is just a simple string', class:'mytooltip'}">{{cellContent.substring(0, 19)}}...</span> -->
<span class="icon-info-outline" v-tooltip.right="{ html: 'wildcardContent', class:'mytooltip' }"></span>
<div id="wildcardContent">
<p>This Fails and is displayed in the td</p>
</div>
</div>
</td>
<td v-else >{{cellContent }}</td>
v-tooltip="{ content: `<h1>Hellow World</h1>` }"

Knockout: HTML-binding in text-binding

Depending on the outcome of an expression in my text data-binding,
I would like to display a property or some HTML code.
This is the expression:
resultsCount().length > 0 ? resultsCount().length : {html: loadingIcon}
And it's being used in the following context:
<span data-bind="text: resultsCount().length > 0 ? resultsCount().length : {html: loadingIcon}"></span></strong></p>
This obviously doesn't work (because of {html: loadingIcon}), but I'd like to know how I can make this work.
The loadingIcon HTML is a simple HTML structure like this:
self.loadingIcon = "<div class='loadingIconWrapper'><i class='glyphicon glyphicon-refresh'></i></div>";
How can I achieve this? Thanks in advance.
You can use just html binding to achieve result.
<span data-bind="html: resultsCount().length > 0 ? resultsCount().length :loadingIcon"></span>
Fiddle demo
Or if you don't want to use html binding for displaying number then use if binding.
<!-- ko if: resultsCount().length> 0 -->
<span data-bind="text:resultsCount().length"></span>
<!-- /ko -->
<!-- ko ifnot: resultsCount().length> 0 -->
<span data-bind="html:loadingIcon"></span>
<!-- /ko -->
Fiddle demo

dropdown multiple options issue

I have a list of contacts, I would like to display the phoneNumbers in inputs with dropdown.
<div id="retrievedContactsDiv" data-bind="foreach: Model.userContacts.contacts()">
<!-- ko if: ($data.phoneNumbers().length >= 1) -->
<div class="control-group span3 offset3 ">
<div class="input-append btn-group">
<input id="appendedInputButton" type="text" data-bind="value:$data.phoneNumbers()[0].phoneNumber()">
<a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#">
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<!-- ko foreach: $data.phoneNumbers() -->
<li><span data-bind="text: $data.phoneNumber()"></span> </li>
<!-- /ko -->
</ul>
</div>
</div>
<!-- /ko -->
</div>
JS
$('.dropdown-menu li span').click(function(){
var elementVal=$(this).text();
$('#appendedInputButton').val('');
$('#appendedInputButton').val(elementVal);
});
My problem is that I can't have same id, if I use class all the phoneNumbers of my contacts list will be modified, How can I do it to display correct value if the user use dropdown ?
http://imageup.fr/uploads/1377867794.jpeg
Use jQuery smart selectors to find the closest common parent and then find the field inside it.
$('.dropdown-menu li span').click(function(){
var elementVal = $(this).text();
$(this).closest('.input-append').find('#appendedInputButton').val(elementVal);
});
Actually this is also wrong (in terms of HTML) because you're stuck with duplicate IDs. I would rather suggest you do the same with a class instead of id, it'll work exactly the same with the suggested JS above.