We have Sitecore SPEAK page which have set of textboxes, radio buttons and combo boxes. We need to automatically fill or autocomplete those fields when the user enter some value to a specific field (lastname).
Does anyone knows how we can do this with Sitecore SPEAK?
What we have tried already:
We have a cshtml file which display the search records which placed inside the SPEAK page under a User lookup section.
When the user enter some value to lastname field, we retrieve data from the database and display it.
this.on("change:input", this.users, this); // defined in the initialize method
//User function to load records
users: function () {
var input = this.get("input");
$.ajax({
url: "/api/sitecore/Order/FindUsers",
type: "POST",
data: { input: input },
context: this,
success: function (data) {
this.set("output", data);
}
});
}
//CSHTML code
#using Sitecore.Mvc
#using Sitecore.Mvc.Presentation
#using Sitecore.Web.UI.Controls.Common.UserControls
#model RenderingModel
#{
var rendering = Html.Sitecore().Controls().GetUserControl(Model.Rendering);
rendering.Class = "sc-UserList";
rendering.Requires.Script("client", "UserSearch1.js");
rendering.GetString("input", "input");
var htmlAttributes = rendering.HtmlAttributes;
}
<div #htmlAttributes >
<p id="eventTitle"></p>
<table class="table table-hover">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody data-bind="foreach: output">
<tr>
<td><a data-bind="text: FirstName, click: function (data) { loadData('data-sc-id'); } "></td>
<td data-bind="text: LastName"></td>
</tr>
</tbody>
</table>
<script>
function loadData(attribute) {
var matchingElements = [];
var allElements = document.getElementsByTagName('*');
for (var i = 0, n = allElements.length; i < n; i++) {
if (allElements[i].getAttribute(attribute) !== null) {
if (allElements[i].accessKey == 'newitem1') {
allElements[i].innerHTML = "testtt";
allElements[i].innerText = "testtt";
}
matchingElements.push(allElements[i]);
}
}
return matchingElements;
}
</script>
</div>
Once the user click on particular record in the User lookup section, we need to fill or autocomplete the rest of the fields in that page with the retrieved values but we were not able to do so.
Since we don't have a specific id to capture and set the value, we have set an accessKey and located the control we want but when we set the innerHTML or innerText it does not reflect.
So any one knows how we can do autocomplete with sitecore SPEAK?
Quite a broad question, but looking at the docs and in the Business Component Library, AdvancedComboBox might be suitable.
https://doc.sitecore.net/speak/components/advancedcombobox
This has the ability to search for items as the user is typing in the combobox.
Related
I am using Ember Version 2.5.1
I have setup checkbox, and they work when selected. But, when I select one box, for one user, all the boxes become selected for all the users. E.g if I select a team (Speedy) for Sophie, then everyones checkboxes end up checked and being on team Speedy. How do i stop this? And make it so each person can be on a different team.
e.g. the out come is a list of everyones names, (then if 'Team Speedy' is checked), next to everyones name is 'Team Speedy'.
teams.hbs;
<div class="container">
<table class="table">
<thead class="thead-inverse">
<tr>
<th>Name</th>
<th>Team Speedy</th>
<th>Team Alpha</th>
<th>Team Invincible</th>
</tr>
</thead>
<tbody>
{{#each model as |signed-player|}}
<tr>
<td> {{signed-player.name}} </td>
<td> {{input type='checkbox' checked=speedy}} </td>
<td> {{input type='checkbox' checked=alpha}} </td>
<td> {{input type='checkbox' checked=invincible}} </td>
</tr>
{{/each}}
</tbody>
</table>
{{#each model as |signed-player|}}
<p><b>{{signed-player.name}}</b> is on the following team: <b>{{teamName}}</b></p>
{{/each}}
</div>
controllers/team.js
speedy: false,
alpha: false,
invincible: false,
teamName: function()
{
if ( this.get('speedy') ) {
return 'Team Speedy';
}
else if ( this.get('alpha') ) {
return 'Team Alpha';
}
else if ( this.get('invincible') ) {
return 'Team Invincible';
}
else {
return 'No team yet';
};
}.property('speedy', 'alpha', 'invincible'),
The main problem I see in your example, is you are not setting any properties on any of the players. You are computing only one property {{teamName}} and just displaying it once per player, which is why clicking one checkbox appears to change the team for everybody... when in reality you are not actually setting any players onto any teams at all.
The other problem i see: you need to decide if chackboxes are the right UI for your selection. can a single player be on more than one team? if so, then checkbox is fine.. if not, then a select box or a set of radio inputs are probably better.
All that being said... each player object/record needs a property that actually stores the value representing which team(s) they belong to.
You will also need an action from each checkbox/radio/select/whatever to actually set the selected value onto the player object:
Here is my example:
https://ember-twiddle.com/1fe44ad4dc0494973c494a624ead79b7?fileTreeShown=false&openFiles=templates.application.hbs%2C
there are a number of things going on here... but essentially what we are doing is using a select input of choice (for me.. radio) and using the change action from the input to set each specific player's team property... which is defined on each player object to begin with.
I use a mut helper in my action in the example.. is is a quick way to set a value in a template action.. if you wanted to use a checkbox instead.. you will most likely want to replace the mut helper and apply your own custom action in a controller.
Please follow up if you need/want any extra explianation
I'm creating a dynamic table component (one row per model), that will include components dynamically (one column for each object in config, each object relates to a key in a model).
I'm trying to bind the model key to the dynamic model.
Any ideas on how to do that given the following?
Config object:
deployment.js (controller)
EDConfig: {
controller: this,
modelType: 'EscalationDetailModelGroup',
table: {
cols: [{
header: 'Escalation Time',
cname: 'form-input-text',
content: {
value: model.escalationTime //obviously this wont work
}
},{
header: 'Most Complex Alarm Level',
field: 'mostComplexAlarmLevelDispatched',
cname: 'form-input-text',
content: {
value: model.escalationTime //obviously this wont work
}
}]
}
};
Router Model:
deployment.js (router)
modelRange: [{
id: 1,
escalationTime: '3 hours',
mostComplexAlarmLevelDispatched: 'N/A'
}, {
id: 2,
escalationTime: '45 minutes',
mostComplexAlarmLevelDispatched: 'Level 3'
}]
Templates:
deployment.hbs
<h2>Deployments</h2>
{{table-list
config=EDConfig
data=model.escalationDetailModelGroups
}}
table-list.hbs
<table>
<thead>
<tr>
{{#each col in config.table.cols}}
<th>{{col.header}}</th>
{{/each}}
</tr>
</thead>
<tbody>
{{#each record in modelRange}}
<tr>
{{#each col in config.table.cols}}
<td>
{{component col.cname content=col.content}}
</td>
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
I'm still not sure how are you trying to merge/link the data, but I doesn't seem to be really important.
I don't think its necessary to pass two data sources to your table-list, the relationships between config and model are not something that you should be doing in the templates. Its more of a data-decoration process and that type of thing should be done at the controller level.
How about something like:
// controller
tableRows: function() {
var config = this.get('config');
var model = this.get('model');
config.forEach(function(col) {
// give each col a model reference
});
return config;
}.property('config', 'model')
// template
{{table-list data=tableRows}}
I just typed that off the top of my head, tweaks would be needed most likely, but the idea should be clear.
How can I specify a class to an item when clicked with Ember. I am using a Handlebars action on the elements of a table to sort by properties. I want to add a class to the property being sorted so I can show the user the current property being sorted. How can I do this?
I have an ember controller shown below:
App.UsersController = Ember.ArrayController.extend
title: 'Users'
count: Ember.computed.alias 'length'
sortProperties: ['username']
actions:
sort: (property) ->
console.log property
if #get('sortProperties')[0] is property
#set('sortAscending', !#get 'sortAscending')
else
#set 'sortProperties', [property]
#set('sortAscending', true)
The controller allows me to click on headings in a table to sort the table. The html is shown below:
<thead>
<tr>
<th>Action</th>
<th class="sort" {{action sort 'last'}}>Last</th>
<th class="sort" {{action sort 'first'}}>First</th>
<th class="sort" {{action sort 'username'}}>Username</th>
<th class="sort" {{action sort 'email'}}>Email</th>
</tr>
</thead>
Create a currentSort property (optional)
First, I created a currentSort property on your App.UsersController which cleans a little bit the code. We'll use it later.
App.UsersController = Ember.ArrayController.extend
sortProperties: ['username']
currentSortBinding: 'sortProperties.firstObject'
actions:
sort: (sort) ->
if sort is #get('currentSort')
#toggleProperty 'sortAscending'
else
#setProperties
currentSort: sort
sortAscending: true
Define a custom view for each <th>
You'll then have to define a custom view for the <th> which will do 2 things:
Have a class active-sort when the sort of the view is the current
Change the controllers current sort when clicking the view
It will looks like this:
App.SortView = Ember.View.extend
template: Ember.Handlebars.compile('{{view.sortName}}')
tagName: 'th'
sortName: null # (will be different for each <th> : `last`, `first`,..)
classNameBindings: [ ':sort', 'isCurrent:active-sort' ]
isCurrent: (->
#get('sortName') is #get('controller.currentSort')
).property('sortName', 'controller.currentSort')
click: ->
var newSort = #get('sortName');
#get('controller').send('sort', newSort);
Here we customized the view class names, and we handled click event on the view.
Insert a custom view for each sort
This is really simple to insert views in templates:
<thead>
<tr>
{{view App.SortView sortName="default"}}
{{view App.SortView sortName="price"}}
{{view App.SortView sortName="alphabetical"}}
</tr>
</thead>
You can test all of this in a working JSBin
I don't know if this is the best workaround, but you could have some "sort flag" that you could bind CSS on.
In your controller (in "classic" javascript) :
sortedByLast : function() { return this.get("sortProperties")[0] === "last" }.property("sortProperties.#each")
// etc ...
In your template :
<th {{bind-attr class=":sort sortedByLast:current-sort"}} {{action sort 'last'}}>Last</th>
So the sort class would always be on, and the current-sort would only be there if it match its proper flag.
I am trying to create a simple page where I loop through a list of phone numbers associated with a Contact. Each phone number has a "number" and a "phone_type".
I've created a View that extends Ember.Select that populates itself with a the list of phone_types. Other than that, is's just a plain Ember.Select:
export default Ember.Select.extend({
thestore: '',
optionLabelPath: 'content.code',
optionValuePath : 'content.code',
didInsertElement: function() {
var vtype = this.get("valuetype");
var vls = this.get("thestore").filter('valuelist', { type: 'phone_type' }, function(vv) {
return vv.get("type") == vtype;
});
this.set("content",vls);
}
});
Here is my code in the template using the "valuelist" view defined above.
{{#each phonenumber in model}}
<tr>
<td> {{phonenumber.number}}</td>
<td>{{phonenumber.phone_type}}</td>
<td>{{view 'valuelist' thestore=store valuetype='phone_type'
selection="{{phonenumber.phone_type}}"
value="phonenumber.phone_type" }}</td>
</tr>
{{/each}}
What I cannot figure out is how to bind the value in the dropdown to the field in each model record I am iterating through in the template. You can see I've tried various things in the code above without any luck.
The property you need is value. However, in your attempts above, you were filling it with literal strings. This happens when you provide a value wrapped in quotes ('...' or "..."). What you need is to give it an identifier, which is value without quotes. So, try this:
{{#each phonenumber in model}}
<tr>
<td>{{phonenumber.number}}</td>
<td>{{phonenumber.phone_type}}</td>
<td>{{view 'valuelist' thestore=store valuetype='phone_type'
value=phonenumber.phone_type }}</td>
</tr>
{{/each}}
As an aside, this is a very unortodox way of doing things. A view shouldn't be tied to a store. Also, I think this will cause your select to be unusable while the values load asynchronously (and potentially crash your app if there is an error).
A conventional way to do this would be to load the list of all phone_types in your setupController hook and then provide it as an argument to Select view.
Controller:
App.MyRoute = Ember.Route.extend({
//...
setupController: function (c, m) {
c.set("model", m);
c.set("phoneTypes", [
"home", "office"
// or whatever, load it from store in model hook and setup here
]);
}
});
Template:
{{#each phonenumber in model}}
<tr>
<td>{{phonenumber.number}}</td>
<td>{{phonenumber.phone_type}}</td>
<td>{{view Ember.Select
content=phoneTypes
value=phonenumber.phone_type }}</td>
</tr>
{{/each}}
imagine you have a table displaying a list of books (like the index does) and you want to make changes in a column called "Sold" (a checkbox for example).
So once you finish "Checking" the books you have sold, you want to save that in the database. How do you send back that list to the controller and update it?
So, the code is something like this, in the controller:
def aMethod(){
...
[bookInstanceList: myBookList]
}
In the GSP:
<g:each in="${bookInstanceList}" status="i" var="bookInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${bookInstance.id}">${fieldValue(bean: bookInstance, field: "author")}</g:link></td>
<td><g:checkBox name="sold" value="${bookInstance?.sold}" /></td>
<td>
</tr>
</g:each>
The idea is with the checkbox let the user change the "Sold" value from that book. How can I save my new bookInstanceList?
Thank you very much
From what I see you want to dynamically update the backend as the user clicks the check box?
If so then you need an ajax call something like this would do it:
<g:each in="${bookInstanceList}" status="i" var="bookInstance">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${bookInstance.id}">${fieldValue(bean: bookInstance, field: "author")}</g:link></td>
<td><g:checkBox name="sold" value="${bookInstance?.sold}" onChange="TriggerFilter(this)" /></td>
<td>
</tr>
</g:each>
<g:javascript>
function TriggerFilter(e) {
if (e.checked==true) {
$.get('<g:createLink action='Your_Action' controller="YourController"
params="[ filterbind: ''+attrs.filterbind+'',term:''+attrs.term+'' ]"/>'
,function(data){
$('#FilterField').hide().html(data).fadeIn('slow');
});
}else{
$('#FilterField').hide().html('').fadeIn('slow');
}
}
</g:javascript>
<div id="FilterField" class="filterField">
{Result returned in here}
</div>
You need to fit it e.value into the params take a look at grails java script get createLink there are lots of examples in my plugin here:
https://github.com/vahidhedayati/ajaxdependancyselection/tree/master/grails-app/views
and I would suggest looking online/reading on how to use it
You may wish to change the get to :
how to use grails ${createLink} in javascript
var url = '${createLink(controller:'Books', action: 'update')}' + e.value ;
$.get(url ,function(data){
$('#FilterField').hide().html(data).fadeIn('slow');
});
}else{
$('#FilterField').hide().html('').fadeIn('slow');
}
}