How to select an item from a combobox in Senchat Test - extjs

Is there a way to select an item from a combobox without having the actual value of the item ?
Lets say we have a combo with Oranges, Apples and Lemons and the actual value of these items are keys that we don't know is there a way to do select by index ?
Or perhaps to retrieve the value based on the displayValue ?
Something like this works:
this.comboBox().setValue(7);
But what if I only have the displayValue of what I want to select? Lets say 'Oranges', how do I select that from the combo ?

One way you could do this would be via execute(). The idea would be to find the correct record in the combobox's store, retrieve the id from that, and then use the id to set the correct value.
In an in-browser scenario, you could just do this directly by inspecting the combobox's store. However, in a WebDriver-based scenario, you don't have access to the context in which the app is running from the spec, so execute() is the easiest way (where there is no other way via the API) to get in there. Here's a simple example:
// Component
Ext.define('Sandbox.view.test.combobox.Base', {
extend: 'Ext.form.field.ComboBox',
id: 'futureCmp',
displayField: 'text',
valueField: 'id',
store: {
fields: ['id', 'text'],
data: [
[1, 'Apples'],
[2, 'Oranges']
]
}
});
// Spec
it('should select correct value from displayField', function () {
var combo = ST.comboBox('#futureCmp');
combo
.execute(function (cmp) {
// we're in the target context now, so we *can*
// interact with Ext JS now
// we could return an object if needed, but we only need the id
return cmp.getStore().findRecord('text', 'Oranges').get('id');
})
.and(function () {
// "executeResult" is the value returned from execute()
// in this case, it's the id of the item we want to select
var id = this.future.data.executeResult;
combo.setValue(id);
// assert that the value has been correctly selected
combo.value(id);
});
});
The nice part about this approach is that it's portable between scenario types; since we're using the API exclusively, we could easily switch between in-browser and web-driver based scenarios and run the same test (in fact, this is borrowed from some internal tests that do precisely that).
Finally, we do have an item in the feature request tracker for adding select() style methods to the combobox future API, similar to what is available for Grid and DataView. I'm not sure when they will make it in, but I've personally been wanting it for a while :)

You can do something like this: ST.ComboBox('${ST_LOCATOR}').setValue('STRING_VALUE')
Where STRING_VALUE is one of the options available in the combobox.
Please note that STRING_VALUE is not the value you see in UI. you can have in UI 3D Pie and in component 3d_pie. The second is the one you'll have to use.
If the component is not quite a real ComboBox but a more complicated component you'll have to find workarounds with DOM elements and click actions, etc.

Related

Set the value of a different field when a field value changes

I'm using Angular Schema Form and I want to set a model property to null when a field value changes. I've tried using onChange in the form definition like so
{
key: '7_11',
type: 'radios',
titleMap: [{value: 'no', name: 'No'}, {value: 'yes', name: 'Yes'}],
onChange: function(modelValue,form) {
if (!modelValue) {
// model['8_1'] = null
}
}
}
Notice that the model property I'm trying to set is bound to a different field than the field that has changed
I can't do it in the manner indicated by the comment, because model is not in scope in the onChange listener.
Update
A second example is this Plunker demo. Say we want to clear the 2 checkboxes (by removing the corresponding properties from the model) whenever some text is entered in the Name field, how could this be achieved?
I should also point out that for reasons I won't bore you with, I can't implement this using a conditional and destroyStrategy.
Well, it is not uncommon (because it is kind of natural) to set the model and the form inside the scope of the same controller.
If that is the case, you can set X by $scope.model.X = modelValue.
Or perhaps you are in a position where you can't reach the scope of the model, in that case it is more complicated. On the other hand I would recommend to do it all in the same place.
(Sometimes that is not possible. For example, I have dynamic forms and schemas in my application, however in those cases I use generalized functionality like the filter functionality in ASFDS or ASF conditions and avoid hard-coding UI using onChange) .
For example, this would set foo2 if foo is changed in the plunkr:
onChange: function(modelValue,form) {
if (modelValue) {
$scope.model.foo2 = ["Yes"];
}
},

Kendo multiselect populate previously selected items using odata with paging. (AngularJS)

I'm using the kendo MultiSelect with odata paging and using the angularJS integration. Populating the data from scratch works great. When I want to re-populate the data from initial data then I seem to have a problem.
Cause of the problem:
The data only gets populate from the initial or previous dataset. So, if I the paging size is 10 then only products that exist in the first page will be displayed as normal. All product that don't fall within the first page will just not be displayed.
Possible workarounds:
Increase the page size. I have used this on other pages where the results are quite small. However this is not a realistic work around as we are expecting much bigger datasets in the future ( hence using odata in the first place)
Was thinking we could possibly do some sort of initial sorting. However this could also be slow and could still be a problem if there were more items selected than exist in the first page.
Ideal solution
Is there a way to tell kendo component to load all data based on current value? This will then build the required odata call and populate the component.
Example of the current issue:
http://dojo.telerik.com/ODaLe/2
I worked 2-4 hours to find a solution for this. Dunno if yall would like it, but it might help somebody, so I'd type it here. Following are the steps:
Step 1: Create the data source
First, setup the dataSource object which you would be using for reading remote data (for offline data, improvise by reading the API).
var dataSource = new kendo.data.DataSource({
dataType: "jsonp",
transport: {
read: {
url: options.source,
type: 'POST'
},
},
serverFiltering: true
});
Step 2: Load the selected items
This can be tricky as you need to have the selected item IDs on the client side. For me, I did it by adding a data-options-selected="1;3;9" attribute to my select element. Later, in my JavaScript, I split this attribute by ";" and retrieve an array of selected IDs. Lets say these values are in var valuesArray;
Once we have an array of selected IDs, we need to read them from the data-source. In my case, it was remote, so I ran a dataSource.read() with filters as under:
dataSource.read({
filter: {
logic: 'and',
filters: [
{
field: options.dataValueField,
operator: 'equals',
value: options.value
}
]
}
});
On the server side, this should return an array containing the items having the given identifiers. Thus, we now have those items on the client-side as well.
Step 3: Set values for the widget
Now that the value related data is loaded, we can set the values for the widget using the values() method. Here, $el is the jQuery object representing the select element which I was using for multiSelect.
var oWidget = $el.data('kendoMultiSelect');
oWidget.value(valuesArray);
That's it! One multiselect widget pre-loaded with values, ready to rock and roll. Served my purpose. Dunno if any short-cuts exist.
When using Kendo with Angular, you want to use the k-rebind attribute to refresh the pulldown options + update the picker with the values in your $scope.countries object when it changes.
If you want like the picker to update when $scope.products changes as well, you can initialize the picker using a k-options attr pointed to an object in your controller, and set the k-rebind to that object.
This kendo tutorial provides a useful example, also using odata paging.
http://docs.telerik.com/kendo-ui/web/multiselect/how-to/AngularJS/pre-select-items

AngularJS - Filtering by multiple checkbox groups

I'm looking for a bit of advice on what's the best way to go about this:
I have about 5 groups of checkboxes. The list would be something like brands, model, colour, size and so on. As a user ticks off a brands, colours etc a list of cars get updated based on their selections.
The list is generated from a call to the database, I know it would be fairly straightforward if the list was generated once as a list that could be filtered entirely on the frontend but the DB is expected to grow to over 10,000 rows so that wouldn't be ideal.
My thinking at first was to post to the DB each time a checkbox is ticked and return the result to the view. This works fine for one set of checkboxes but I can't get my head around how to do it with multiple checkbox groups.
Here's the function in my controller that handles that:
$scope.getSelectedBrands = function() {
$scope.brandsselected = $filter('filter')($scope.brands, {checked: true});
var senddata = $filter('filter')($scope.brands, {checked: true});
$http.post('/brands', senddata).success(function(data, status, response) {
$scope.cars = data;
});
}
I don't know if using a different but very similar function for each checkbox group would make too much sense and doesn't seem very DRY. At the moment each checkbox group e.g brand would have it's own URL to post to to return the set of results. Also since a checkbox in any of the checkbox groups could be ticked first the initial data would be returned from a different function depending on what checkbox was checked.
Is there a better way to approach this? I also would need to allow users to uncheck a checkbox and repopulate the list again.
Hopefully that makes sense.
Thanks
OK I think I was approaching it the wrong way. All I needed to do was to create a function like the below and fire it whenever a checkbox is checked. It just gets call the form data.
$scope.getFormdata = function(){
var formdata = [{
brands : $filter('filter')($scope.brands, {checked: true}),
types : $filter('filter')($scope.types, {checked: true})
}];
console.log(formdata);
}
Very straightforward.

How to find Table and append a new record to its Store?

I need to update a Store based on some information that I have.
I have a table in the document, that uses some Store to keep data,
and in separate part of page I have a button that needs to add some information to the Store (and table). I got a bit confused, so, I just ask here all I need to know:
Which property in table configuration needs to be specified to locate table later?
Which call I need to make to find the table and locate its store?
How I can generate and append data to the table's existing store?
The "table" you are referring to is Grid in ExtJS terminology.
1. To get the grid for later use, you need a reference to that object. There are many ways in ExtJS to get hold of this reference.
Using Javascript Variables: Most simple way is to have a javascript variable that will hold the reference. This is usually done when the grid is created. For example:
var myGrid = Ext.create('Ext.grid.Panel', {
// All the configs...
});
You can use the myGrid variable to get access to the grid.
Using ComponentManager: When an ExtJS component is created, it gets registered with the component manager. You can always get hold of an ExtJS component from this register. The manager tracks each component with a unique id. To use this method, you will have to define a unique id for your grid component and later use the famous Ext.getCmp() method. Here is an example:
var myGrid = Ext.create('Ext.grid.Panel', {
id: 'myGrid', // Unique id for the grid
// All other configs...
});
Using this method is NOT the best practice.
Using itemId and Component Query: A better method than the above two; you can use the itemId config and ComponentQuery. ComponentQuery class provides a selector-based searching for Sencha Components analogous to DOM querying. Example:
var myGrid = Ext.create('Ext.grid.Panel', {
itemId: 'myGrid',
// All other configs...
});
And to get a reference, you may call the query() method from a container or use Ext.ComponentManager (this is global).
Accessing in MVC controller: If you are developing your application using MVC, you can make use of this method. A controller have reference array namely: refs. (Internally, the method makes use of ComponentQuery and selectors to access the component). Refer MVC guides and examples to see how this works..
2. Once you obtain the grid with any the above techniques, you can get the store simply by calling the method: getStore(). This returns the store object (Ext.data.Store). Example:
myStore = myGrid.getStore();
3. Refer the Ext.data.Store documentation. you can manipulate your grid's store using methods like add(),load(),remove() etc...
FYI.
It is not
Ext.Cmp()
it is
Ext.getCmp('myGrid')

EXTJS ReRendering of the Grid with Datastore

I have a grid made with ExtJS, and I render it to a div that I define, when a refresh is requested I simply "empty" the div using JQuery and then re-render the grid creating new objects each time:
var grid = new xg.GridPanel({
store: store,
columns: [
...
renderTo: 'db-grid'
And then to empty the div I use this:
$("#db-grid").empty();
This works well for like 3 or 4 refreshes, and then it seems to load really slowly, I imagine this is because it re-creates all these objects again, the only thing that changes each time is the "store." I acquire that through an AJAX request, is there a way to refresh this without creating a new grid each time?
I'm pretty new to ExtJS, and I'm making a bit of a transition here from JQuery, which is why I'm using the "empty()" function from JQuery, if you know of a ExtJS alternative, I would be glad to use that instead,
Thanks!
Take a look at Store's load(Object options) and reload(Object options) methods at http://dev.sencha.com/deploy/dev/docs/.
An example of this functionality can be seen in Ext.PagingToolbar. This class contains a button that refreshes a Grid and its Store, without destroying the Grid each time:
// private
doLoad : function(start){
var o = {}, pn = this.getParams();
o[pn.start] = start;
o[pn.limit] = this.pageSize;
if(this.fireEvent('beforechange', this, o) !== false){
this.store.load({params:o}); // here is the call you're interested in
}
},
doLoad() is then simply called from the method doRefresh():
doRefresh : function(){
this.doLoad(this.cursor);
},
I included this code for the sake of a complete example, but really all you need to worry about is the load() or reload() methods. Make sure to read the API to see a full list of arguments that can be passed into the methods.

Resources