Sitecore SPEAK UI programmatically set selected item of ComboBox - javascript

How should I set the selected item of a ComboBox component in Sitecore SPEAK UI?
My ComboBox is populated by a QueryDataSource component which is looking at a folder of items in my core DB.
I can retrieve the currently selected value (which is text, not an ID) using the following code:
var value = this.MyComboBoxId.viewModel.selectedItemId();
and I would have expected to be able to set the selected value using:
var value = "SomeValueWhichExistsInTheList";
this.MyComboBoxId.viewModel.selectedItemId(value);
but this doesn't seem to work. The documentation here mentions using
rebind(items, selectedItem, selectedValue, displayFieldName, valueFieldName)
but I don't want to have to re-populate it, just change the selected item. My code is within the initialize method of my model.
Edit
I found that if the ComboBox does not have DisplayFieldName or ValueFieldName values set in the rendering properties you have to set the value to the appropriate itemId. DisplayFieldName and/or ValueFieldName should be set to the name of a field you have created - you cannot bind to the item name.

In the initialize method, use the following code to set the value:
app.yourQueryDataSource.on("change:hasItems", function () {
app.yourComboBox.set("selectedValue", yourValue);
});

Above approach did not work for me and hence i used the
app.<yourcontrolid>.viewModel.rebind()
function as documented in Sitecore SPEAK combobox documentation and that worked.

Related

Unable to toggle drop down value based on other column

I need to make dropdown value in Ag-Grid dynamically changed based on value/condition of another column.
Already tried to toggle it with a function, extend it with Vue framework to make it reactive, and also with gridOptions.api.setColumnDefs but still no luck. (value changed on console but not rendered).
here's a snippet and screenshot.
colDef = [
{'headerName': 'Steps',
cellEditor: 'select',
cellEditorParams: {
values: store.globalData.stepsValues } // global var, change works on console
}]
Steps column dropdown values here needs to dynamically changed based on a condition.
Finally I made them reactive by injecting colDef parameter to Vue component, so it's now a reactive data.

Adding text fields dynamically in Meteor without using jquery

I have a simple application form. On click of one button I just need to add text fields and on click of another button, just remove text field dynamically.
How can this be done in meteor without using jQuery as I have seen many blogs that says it is not a good practice to use jQuery with meteor. Can any tell me how can this be achieved without using jQuery.
You can use a reactive variable and a helper that returns an array based on that reactive variable to construct template-level {{#each}} statements. A good choice for a reactive variable is the Session variable, since it's built into Meteor (you won't need the ReactiveVar package or to set up your own dependencies).
Then, you can use event handlers to update the reactive variable as appropriate. For example...
//client only code
Template.test.onCreated(function() {
Session.set('inputs', []); // on page load, set this to have no inputs
});
Template.test.helpers({
inputs: function () {
return Session.get('inputs'); // reactively watches the Session variable, so when it changes, this result will change and our template will change
}
});
// Now we'll set up a click handler to add inputs to our array when we click the "add" button
Template.test.events({
'click #add-input': function () {
var inputs = Session.get('inputs');
var uniqid = Math.floor(Math.random() * 100000); // Give a unique ID so you can pull _this_ input when you click remove
inputs.push({uniqid: uniqid, value: ""});
Session.set('inputs', inputs);
}
});
// We also need handlers for when the inputs themselves are changed / removed
Template.input.events({
'click .remove-input': function(event) {
var uniqid = $(event.currentTarget).attr('uniqid');
inputs = Session.get('inputs');
inputs = _.filter(inputs, function(x) { return x.uniqid != uniqid; });
Session.set('inputs', inputs);
},
'change input': function(event) {
var $input = $(event.currentTarget);
var uniqid = $input.attr('uniqid');
inputs = Session.get('inputs');
index = inputs.findIndex(function(x) { return x.uniqid == uniqid; });
inputs[index].value = $input.val();
Session.set('inputs', inputs);
}
});
Your templates would look something like...
<template name="test">
<button id='add-input'>
Add Input
</button>
{{#each inputs}}
{{> input}}
{{/each}}
</template>
<template name='input'>
<input name='testinput' class='test-input' type='text' uniqid="{{uniqid}}" value="{{value}}">
<button class='remove-input' uniqid="{{uniqid}}">Remove</button>
</template>
As per Ibrahim's comment below, if you want to delete the text fields, you'll need to keep track of the values in the text fields and repopulate them every time you delete an element. You can see the full work-up in action here. Note that in order to do this, I cheated and actually did use jQuery, because it was way easier to do it that way (at least for me).
A jQuery-less alternative might involve rigging up the onCreated function to store a reference to each input template instance, from which you might be able to pull the necessary information, but per this question there is no way to get all instances of a particular template through the Meteor API, which would be the easiest way to do it without jQuery.
Edit:
MeteorPad no longer exists -- The code above includes handling adding and removing a specific input using the reactive Session variable. I am now maintaining the current value of the input in the Session variable, and I use this new value property to populate the value every time the inputs are re-populated (when the Session variable updates).
You can see that constantly reading stuff off the screen and updating the array of inputs in the Session variable is quite manual and tedious -- which makes me think this is probably not the best way to be doing this.
One possible solution would be to use session variables. When the button is clicked, set the value of the session variable to what you want. In your template you can show the value of the session variable wherever you need.
Also, jquery is automatically included in meteor. There are definitely places to use jquery in meteor apps. May even be cleaner than using session variables in places. Depends on the situation.

Dojo 1.9: Dijit: Disabling option items in a dijit/Form/FilteringSelect that was populated using a store

I am trying to disable option items in a dijit/Form/FilteringSelect control that is populated using a store.
Following this guide: http://dojotoolkit.org/documentation/tutorials/1.9/selects_using_stores/
It seems to be only possible if the Select control was created without using a store. I have deduced this from debugging the FilteringSelect example. I have tried two methods to disable an item:
Following the advice in this thread: How to disable a single option in a dijit.form.Select?. However, the "stateStore" store object in the FilteringSelect example does not have an 'options' property.
Attempting to access the appropriate element in the store object. For example, in the FilteringSelect example, I do the following:
var optionItem = stateStore.get("AZ");
optionItem.disabled = true;
stateStore.put(optionItem);
select.startup();
Neither method seems to work, so it seems that the only way to have disabled items in Dijit Select controls is to use the options property instead.
Thanks in advance for a solution!
There is a difference between the data in your store (which is in fact the business data) and your rendered data (containing view logic). If you use a store, you're actually feeding your rendered data with your store.
To alter the rendered data (= the options in your select), you need to use the getOptions(idx) method of the dijit/form/Select as you can read in the API documentation. To alter the disabled state of the option you can use:
registry.byId("mySelect").getOptions(myId).disabled = true;
That's all you need. Changing the store data won't help, since it represents business data, not view data. I also made an example JSFiddle where the second option is disabled.
for dojo 1.10 and upto 1.x latest version, you need to add a line of code to update the selection UI:
registry.byId("mySelect").getOptions(myId).disabled = true;
registry.byId("mySelect").updateOption(myId);

Dojo: Getting access to the clicked item in a dijit.form.Select?

I have a dijit Select widget and need to do something when the user clicks one of the dropdown items. Meaning I need access to the clicked item, to retrive some information, and call one of my own functions.
I've tested to attach an onChange on the select and I can get the text value selected fine. But I need the object and not the value. The object holds more values in a data-info-attribute.
Basically what I'm trying to achieve is to show one value in the list but send along more values to populate other fields when selected.
Background: This is a typeahead field populated thru AJAX by a server function. There IS a store attached but it's empty (as far as I can tell) so I've been unsuccessful trying with: .store.fetchItemByIdentity - always returns nothing.
ta.store.fetchItemByIdentity({
identity: ta.getValue(),
onItem: function(item, request){
console.log(item),
console.log(request)
}
})
I expect the log to show item- and request-object, but they're both undefined.
ta.getValue() get's the selected value as expected.
What's the best way to achieve this?
Have a look at my answer to onChange not sufficient to trigger query from Dojo Combobox and also to jsFiddle mentioned there. I added code specific for your needs there:
select.dropDown.on("itemClick", function(dijit, event) {
var node = dijit.domNode;
console.log(domAttr.get(node, "data-info-attribute"));
// or
console.log(node.dataset.infoAttribute);
});

data-win-bind issues: converter only runs once and unable to bind id of element

I have the following html that is bound to an object containing id and status. I want to translate status values into a specific color (hence the converter function convertStatus). I can see the converter work on the first binding, but if I change status in the binding list I do not see any UI update nor do I see convertStatus being subsequently called. My other issue is trying to bind the id property of the first span does not seem to work as expected (perhaps it is not possible to set this value via binding...)
HTML:
<span data-win-bind="id: id">person</span>
<span data-win-bind="textContent: status converter.convertStatus"></span>
Javascript (I have tried using to modify the status value):
// persons === WinJS.Binding.List
// updateStatus is a function that is called as a result of status changing in the system
function updateStatus(data) {
persons.forEach(function(value, index, array) {
if(value.id === data.id) {
value.status = data.status;
persons.notifyMutated(index);
}
}, this);
}
I have seen notifyMutated(index) work for values that are not using a converter.
Updating with github project
Public repo for sample (not-working) - this is a really basic app that has a listview with a set of default data and a function that is executed when the item is clicked. The function attempts to randomize one of the bound fields of the item and call notifyMutated(...) on the list to trigger a visual updated. Even with defining the WinJS.Binding.List({ binding: true }); I do not see updates unless I force it via notifyReload(), which produces a reload-flicker on the listview element.
To answer your two questions:
1) Why can't I set id through binding?
This is deliberately prevented. The WinJS binding system uses the ID to track the element that it's binding to (to avoid leaking DOM elements through dangling bindings). As such, it has to be able to control the id for bound templates.
2) Why isn't the converter firing more than once?
The Binding.List will tell the listview about changes in the contents of the list (items added, removed, or moved around) but it's the responsibility of the individual items to notify the listview about changes in their contents.
You need to have a data object that's bindable. There are a couple of options:
Call WinJS.Binding.as on the elements as you add them to the collection
Turn on binding mode on the Binding.List
The latter is probably easier. Basically, when you create your Binding.List, do this:
var list = new WinJS.Binding.List({binding: true});
That way the List will call binding.as on everything in the list, and things should start updating.
I've found that if I doing the following, I will see updates to the UI post-binding:
var list = new WinJS.Binding.List({binding: true});
var item = WinJS.Binding.as({
firstName: "Billy",
lastName: "Bob"
});
list.push(item);
Later in the application, you can change some values like so:
item.firstName = "Bobby";
item.lastName = "Joe";
...and you will see the changes in the UI
Here's a link on MSDN for more information:
MSDN - WinJS.Binding.as
Regarding setting the value of id.
I found that I was able to set the value of the name attribute, for a <button>.
I had been trying to set id, but that wouldn't work.
HTH
optimizeBindingReferences property
Determines whether or not binding should automatically set the ID of an element. This property should be set to true in apps that use Windows Library for JavaScript (WinJS) binding.
WinJS.Binding.optimizeBindingReferences = true;
source: http://msdn.microsoft.com/en-us/library/windows/apps/jj215606.aspx

Categories