I've searched the examples and docs and I couldn't find if its possible to use wildcards in the ComponentQuery query. Id like to do the following:
Ext.ComponentQuery.query('button > menu > menuitem[text="Welcome*"]');
Since the button text will be the current user name for example "Welcome Shaun".
Try
Ext.ComponentQuery.query('menuitem{text.search( \'Menu Item\' )!=-1}');
Per the docs, you can use custom expressions. This works for the code I've included below:
var toolbar = Ext.widget('toolbar', {
items : [
{
xtype:'splitbutton',
text: 'Menu Button',
iconCls: 'add16',
menu: [{text: 'Menu Item 1'},{text: 'Menu Item 2'}],
reorderable: false
},
{
xtype: 'button',
text: 'Get matches',
handler: function(){
var match = Ext.ComponentQuery.query('menuitem{text.search( \'Menu Item\' )!=-1}');
console.log( match )
}
}
]
});
Ext.widget('panel', {
renderTo: Ext.getBody(),
tbar : toolbar,
border : true,
width : 600,
height : 400
});
Just for the sake of completeness (and because Member Expressions can crash the query)
As #existdissolve stated you can archive something similar (not the same!) of a wildcard with the use of a Member Expression like in your case
Ext.ComponentQuery.query('button > menu > menuitem{text.search("Welcome")!=-1}');
This will try to perform the native JS search operation on the text property of any found menuitem. No matter if this property exist (or the method) which brings me to the main issue of Member Expressions
What you need to know about Member Expressions
You can use a Member Expressions on nearly every selector but they need to exist on that selector or you end up with a exception which aborts the query (totally, like a exception does).
Here's a simple example. Let's say you want to find a button by it's text. That should be no problem, all buttons need a text, didn't they? This works for quite a time till your customer complains that some buttons don't need text a simple image would be enough. You have forgotten about the query thing and add the button and suddenly parts of your application stop working while you end up with a exception like
Uncaught TypeError: Cannot call method 'search' of undefined
You can try it yourself in this JSFiddle example. Try 'find me' and after that hit the 'add image button' and try it again.
Why does this happen? The Ext.ComponentQuery test neither if property exist nor if the expression exist which can quickly lead to a total fail of the query.
Yes, the example above is simple and you may find the source of the error real quick but it can also be completely different.
What now? I don't want to say to say that you should not use a Member Expression but you really need to care about the side effects that you may face.
Starting with ExtJS 5 functionality was introduced that makes this task much cleaner by allowing matching via regular expressions. The documentation provides further detail, but a solution that solves the posted question would look like this:
Ext.ComponentQuery.query('button > menu > menuitem[text/="^Welcome"]');
Related
I've created a custom section in my Umbraco back-end, and I'm trying to create some forms to capture data however I've been unable to fully understand how the umbraco directives work when it comes to validation.
As an example, I'm trying to capture some basic data and save it using the following:
<form name="myForm">
<umb-property property="form.properties.name">
<umb-property-editor model="form.properties.name"></umb-property-editor>
</umb-property>
<umb-button type="button"
label="Save"
button-style="success"
action="save()">
</umb-button>
And in my controller:
$scope.form: {
properties: {
name: {
alias: 'name',
label: 'Display name',
description: '',
value: '',
view: 'textbox',
validation: {
mandatory: true
}
}
}
I would have thought the 'validation' property would be where I can set the validation necessary on the property, however that doesn't seem to be the case. All that seems to do is highlight the property with a red asterix to indicate it's required rather than do any validation.
I've taken a look at the backoffice documentation here however it's unfortunately lacking any code examples and I'm puzzled how this is supposed to work.
I've looked at the other sections, particularly the create user form to see if I can pick anything up there but the only thing I've noticed is the 'valFormManager' directive which may be involved somehow.
I've also tried the obvious things like putting ng-required on the editor and property but neither has done the trick.
Is there any documentation for any of this? It's quite frustrating trying to work out how it's all supposed to work!
Thanks
I'm trying to mimic the behavior of the Sencha ExtJS example at this URL:
http://examples.sencha.com/extjs/6.0.2/examples/kitchensink/#form-contact
Specifically, they show the code but I don't see any place that cause the circled red exclamation point to be drawn whent he field is required.
I'm also wondering if there is a better way to get the red "*" after each field label. It looks like they repeat the code on every field definition which feels like an anti-pattern to me.
***UPDATE
Per #CD, this is how to get the red icon
defaults: {
anchor: '100%',
labelStyle: 'font-weight:bold;padding:0;',
msgTarget: 'side'
},
For the error icon have a look at msgTarget: 'side':
The location where the error message text should display. Must be one
of the following values:
qtip Display a quick tip containing the message when the user hovers
over the field. This is the default.
Ext.tip.QuickTipManager.init must have been called for this setting to
work.
title Display the message in a default browser title attribute popup.
under Add a block div beneath the field containing the error message.
side Add an error icon to the right of the field, displaying the message in a popup on hover.
none Don't display any error message. This might be useful if you are implementing custom error display.
[element id] Add the error message directly to the innerHTML of the specified element.
For adding the red "*" try this override:
Ext.define('Overrides.form.field.Base', {
override: 'Ext.form.field.Base',
initLabelable: function () {
this.callParent(arguments);
if (!this.allowBlank) {
this.labelSeparator += '<span style="color: rgb(255, 0, 0); padding-left: 2px;">*</span>';
}
}
});
https://fiddle.sencha.com/#fiddle/5do
items:[{
xtype:'timefield',
id:'time',
hideMode:'visibility'
},{
xtype:'checkbox',
labelText:'hide',
listeners:{
change:function(cmp,nv) {
console.log('Checkchange');
if(nv) Ext.getCmp("time").hide();
else Ext.getCmp("time").show();
}
}
}]
I'm using hideMode:'visibility' but TimeField does display:hidden.
Did I do error in code, or is this bug in ExtJS?
This is ExtJS.
The "hidden component is considered hidden so it won't participate in a layout, regardless of the hideMode".
This has been reported as a bug at least twice that I could find, but apparently the developers decided this is what they intended.
See this bug report for the details: hideMode: "visibility" not working for toolbar items?
See this also: BUG: hideMode=visibility does not work for hbox
If you still want to do it though, here is the workaround proposed in the first thread:
component.el.setStyle('visibility', 'hidden');
I'm trying to add a select box to a Backgrid.Grid in order to fire a function that will reset the state: {pageSize} to the value the user selects. But I can't figure out how or where to bind the events to the grid.
My understanding is that the element needs to be part of the view (which I believe is the Backgrid.Grid), so I added the select box to the footer of the grid and gave it an id and tried adding an events parameter and matching function to it, but it does nothing.
So, in my footer I have
select id="changePageSize"
And in the grid
events: {
'change #changePageSize' : 'changePageSize'
},
changePageSize: function(){ console.log('hooray!');}
I believe my approach is completely wrong at this point but can't find anything to direct me down the correct path.
What I ended up doing was adding the event listener and function to the backgrid-paginator extension.
Added the select box to the _.template('...
_.template('...<div class="page-size"><select name="pageSize" class="pageSize"><option...');
Under events I added:
'change select.pageSize' : 'changePageSize'
And then created the function:
changePageSize: function(e){
e.preventDefault();
this.collection.state.pageSize = Math.floor(e.currentTarget.value);
this.collection.reset();
},
It makes sense to make this function and its display optional and to also allow a developer to assign an array to generate custom option values. When I get time.
Regarding Duffy Dolan's answer: everything si great in your example, except if you are on let's say on third page and select to have all results only on one page, you get an error.
You just need to add:
this.collection.getPage(1); // it will always select first page
I seem to be struggling with something I have used a million times! I dont understand why all of a sudden it doesnt work anymore :)
My Layout
an accordion
> toolbar
> tabs
>tab 1
> form.panel 1
> textfield (alias: 'widget.mytextfield')
> form.panel 2
>tab 2
> form.panel 1
Now heres the problem... when im at panel 1 and I try to access the textfield (mytextfield)
//panel, being 'tab 1 > panel 1'
var textfield = panel.down('mytextfield')
It just returns null.
My output for
console.info(panel.down());
is the header of the panel (so im def at the right location) -> it seems as if it cant find the body of the panel
Any ideas? Totally stuck!
The only way I get get 'mytextfield' is with
var textfield = panel.items.items[0];
But if the textfield changes order then the above code wouldnt work anymore of course
Thanks in advance!
UPDATE
Ok, I've figured something out... which is strange
If I take the textfield out of the panel and place it in a separate file. Then include it using requires. I can access the textfield with .down()
For example in my main form panel
...
requires:['App.view.MyTextField'],
items:[{
xtype:'mytextfield' //i can access you with .down()
},{
xtype:'textfield',
alias:'widget.mytextfield2' //you are showing up - but I CANT access you with .down() - only panel.items.items[0]
}]
...
MyTextField
Ext.define('App.view.MyTextField', {
extend:'Ext.form.field.Textfield',
alias:'widget.mytextfield'
});
Any ideas why?
How and where do you get your parent panel component?
http://jsfiddle.net/UBb8n/1/ — works for me.
UPDATED:
According to documentation:
alias:
List of short aliases for class names.
Most useful for defining xtypes for widgets.
So keep in mind that items: {xtype: 'blah'} != Ext.define('My.Class.Blah', {alias: 'widget.blah'}).
First it's just an instantiation of the second one.
And alias: 'widget.mycoolpanel' is just a shorthand for helper function Ext.widget that searches components with xtype: 'widget.<…>'.