in igCombo - How to display in the combo's input the selectedItem's tepmlate - html

I have an igCombo in durandal project. I load the igCombo through the date-bind property at the dom. I created an itemTemplate for the select element options. I want that where I select any item, the combo's input will show the selectedItem template. Here is my code, but it doesn't work well; it shows in the inpute the follow thing:
[object object]
here is my code:
<span id="combo" data-bind="igCombo: { dataSource: data, textKey: 'name',
valueKey: 'id', width: '400px',
itemTemplate: '${name} | ${id}',
allowCustomValue: true,
selectionChanged: function (evt, ui) {
var concatenatedValue = ui.items.template
ui.owner.text(concatenatedValue);}
}">
</span>
(Please don't answer me that I can simply write in the selectionChanged function the sane piece of code that I wrote in the itemTemplate property, becouse now it is small piece of code, but when it will be longer code- it is not nice to write it twice!!!)
can you help me?

I could try to explain why the combo input would not intentionally use the itemTemplate - the template is meant to be mostly rich HTML content (images, links and whatnot as in this sample http://www.infragistics.com/products/jquery/sample/combo-box/templating) and you can't put that in an input field.
However, in your case you are just using text so it is doable - first the ui.items provided to the event (as the name suggests) is a collection, so take the first one and the items don't have template property unless that is part of your model that I can't see.
Like other Ignite UI controls, the Combo uses the Templating Engine and so can you! Take the itemTemplate from the control and the item from the data source like in this snippet:
function (evt, ui) {
var templatedValue = $.ig.tmpl(ui.owner.options.itemTemplate, ui.owner.options.dataSource[ui.items[0].index]);
ui.owner.text(templatedValue);
}
JSFiddle: http://jsfiddle.net/damyanpetev/tB7Ds/
The templating API is much like the old jQUery templating if you are familiar with that - taking a template and then data object.Using the values from the control itself means you can make them as complicated as you want and write them in one place only, this code doesn't need to change at all.

Related

How should I access generated children of a custom HTML component in an idiomatic React way?

I am attempting to create a search bar using a custom HTML component for predictive text input. The way this component is built, it generates several plain HTML children that I need to act on to get full features. Specifically, I need to execute a blur action on one of the generated elements when the user presses escape or enter.
I got it to work using a ref on the custom component and calling getElementsByClassName on the ref, but using getElementsByClassName does not seem like the best solution. It pierces through the virtual and has odd side effects when testing.
This is a snippet of the component being rendered:
<predictive-input id='header-search-bar-input' type='search'
value={this.state.keywords}
ref={(ref: any) => this.predictiveInput = ref}
onKeyDown={(e: React.KeyboardEvent<any>) => this.handleKeyDown(e)}>
</predictive-input>
and the keyDown handler:
private handleKeyDown(e: React.KeyboardEvent<any>) {
// must access the underlying input element of the kat-predictive-input
let input: HTMLElement = this.predictiveInput.getElementsByClassName('header-row-text value')[0] as HTMLElement;
if (e.key === 'Escape') {
// blur the predictive input when the user presses escape
input.blur();
} else if (e.key === 'Enter') {
// commit the search when user presses enter
input.blur();
// handles action of making actual search, using search bar contents
this.commitSearch();
}
}
The element renders two children, one for the bar itself and one for the predictive dropdown. The classes of the underlying in the first are 'header-row-text' and 'value', so the element is correctly selected, but I am worried that this is violating proper React style.
I am using React 16.2, so only callback refs are available. I would rather avoid upgrading, but if a 16.3+ solution is compelling enough, I could consider it.
If you don't have any control over the input then this is the best approach in my opinion.
It's not ideal, but as you're stuck with a 3rd party component you can only choose from the methods that are available to you. In this case, your only real options are to find the element based on its class, or its position in the hierarchy. Both might change if the package is updated, but if I had to choose which would be more stable, I'd go for className.

How to fill Primefaces Autocomplete from Managed Bean

I have a primefaces autocomplete which is shown below:
<p:autoComplete value="#{consultaEventoCargoMBean.idUaSelecionada}" completeMethod="#{consultaEventoCargoMBean.completeUADestino}" var="ua" itemLabel="#{ua.name}" itemValue="#{ua.id}" forceSelection="false" appendTo="#this" />
Where idUaSelecionada and ua.id are Integer and ua.name is a String.
My issue is when I load my page to update the data. My idUaSelecionada is already filled and a object ready to be passed as suggestion (it would be a list of a only element). I was not able to find a way to fill this autocomplete - at least the text component.
Reading the Autocomplete souce code, I saw that there is a List called suggestions. Although there is not a setter for this list, it has a getter. But if I try something like autocomplete.getSuggestions().add(...) I get a NullPointerException. The only way I found to fill this list is through the method indicated by completeMethod tag attribute, who receives a String and returns a List.
I was not able to find in internet how to fill this List. That's why I am asking this to see if anyone has any answers.
Thanks,
Rafael Afonso
You can use JavaScript to trigger execution of method defined in completeMethod tag attribute and load suggestion(s).
Supposing that you want to do it when page loads, add this script to your page
<script>
function triggerSuggestionLoading() {
//finds autocomplete input text field
var autocomplete = document.getElementsByClassName('ui-autocomplete-input')[0];
//sets autocomplete query, for example
autocomplete.value="test";
//simulates key press triggering completeMethod to be executed
autocomplete.dispatchEvent(new Event('keydown'));
autocomplete.dispatchEvent(new Event('input'));
autocomplete.dispatchEvent(new Event('keyup'));
//sets focus on autocomplete
autocomplete.dispatchEvent(new Event('focus'));
//clears autocomplete text
autocomplete.value="";
}
window.onload = function() {
triggerSuggestionLoading();
};
</script>
Actually whenever you refresh your suggestion list and want to load suggestions into p:autocomplete just call triggerSuggestionLoading() method at the end (after all procedures are finished).
I've tested it in Chrome and Edge.

Angular2 function call from html element with no load event (or similiar)

I am new to Angular and have run into a problem that seems to have a javascript work around but they aren't very elegant.
I have a model with an array property. I ngfor the list property to build some html selection options. This is all working nicely. The problem comes when I am trying to set default value...the html elements don't have a load event.
I tried numerous html elements and they don't appear to have a load event either but I certainly could be doing it wrong.
I have seen a solution to put javascript tag right after the html and I could do that but I was really looking for a more elegant way in Angular.
I saw this SO post and thought that was my answer but there is a warning given that I agree with and thus it doesn't appear to be a good solution.
Regardless I tried it just to see if it would work and I got:
Failed to execute 'setAttribute' on 'Element': '{{loadDefaults()}}' is not a valid attribute name
<span {{loadDefaults()}} ></span>
So how can I fire an AS2 function in the component to load the default values?
HTML (btw this is NOT a full page load so there is no body tag):
<tr>
<td *ngFor="let loc of locOptions;">
<span>{{loc.text}}</span>
<input type="radio" name="radiogroup" [value]="loc.value" (change)="onSelectionChange(loc.value)">
</td>
</tr>
Edit
I thought perhaps mistakenly that ngoninit would fire too soon...before the html elements are rendered.
So perhaps what is being suggested is that I add a boolean is default to the model and bind THAT as the element is rendered.
In your ngonit function set this.locOptions to your default values. The value can be changed later on in any function and the change will be reflected in the view. Hope this helps you.
You should use ngOnInit to init you data, and call retrieve your data from your component :
defaults : any;
ngOnInit {
this.defaults = loadDefaults();
}
loadDefaults() {
//get data
}
HTML :
<span>{{defaults}}</span>

Dynamically re-bind html.ValidationMessageFor html helper?

Some background information, I am using ASP.NET with the MVC framework and html helpers.
I currently have a dynamic table where each row has a series of input boxes. Each of these input boxes has a validation message. This works completely fine for the first row. However, when other rows are dynamically added (with the IDs' being changed along with other attributes to match the row number) the validation message no longer works.
Both the row and validation message span are being replicated properly.
In JQuery, this is usually just a problem with the binding, so for each row I would simply re-bind the IDs'. However I am not really to sure how to approach them in ASP.NET.
Any assistance would be appreciated.
Thanks
Alright, I have finally figured this out.
In MVC, in order to handle the validation, it import a JQuery file known as jquery.validate.unobtrusive.js.
However, similar to JQuery, this only occurs at the very beginning when the page is loaded. So, when you add a new dynamic element, you need to remove the bindings and the re-bind them again.
Basically, in your function for adding a new element, put the following lines of code AFTER you have added the new element:
$("#form").removeData("validator");
$("#form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("#form");
For example:
function addInfoDynamic()
{
document.getElementById("#myDiv").innerHTML += "New Content";
$("#form").removeData("validator");
$("#form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("#form");
}

dynamically add a durandal widget

What is the process of adding a widget to a page dynamically? Essentially I have an "Add Widget" button on a view which is hooked up to a function addWidget() in the viewmodel. Basically, when someone hit's the button, I want to dynamically create an instance of a durandal widget and add it to the DOM. My code looks like this:
var addWidget = function () {
var parent = $('<div></div>')
.attr('data-bind', 'widget: { kind:\'myWidget\'}')
.appendTo($('#dashboardContent'))
.get(0);
return widget.create(parent, { id: 'Hello World' });
}
I can see in the browser developer tools that the widget HTML (view) is added to the DOM, but it's not rendering the widget, and activate is not being called on the widget.
What am I missing?
From the looks of it you are trying to use jQuery to add the widget to the DOM. Just thinking out loud the problems are that A: jQuery has no idea what activate is (that is handled by Durandal's router) and B: Nothing will get bound properly. If you are trying to add widgets, why not create an observableArray that contains widgets and just add them into there? That may sound a bit silly, and I am not sure the best way to approach it, but basically it could look like this
In your view model -
var myWidgets = observableArray();
myWidgets.push(someObjectsToComposeTheWidget);
And in your view -
<ul data-bind="foreach: myWidgets">
<li data-bind="widget: {kind:'yourWidget', items: somethingGoesHere, headerProperty:'name'}">/div>
<ul>
This will allow you to dynamically add and display the widgets without having to get messy and use jQuery to display things.