I've looked at many posts on this and have it working to the extent that it does validate my fields when I add the following.
$.validator.setDefaults({
ignore: []
});
The part I'm still missing is adding the input-validation-error class to notify the user. It is working fine for my other input elements (non-kendo). I've tried adding the class manually in $.validator.setDefaults as well but nothing seems to be working.
Is there an example out there somewhere or has anyone gotten it to work?
I'm not certain I'm doing this right but here's what I've tried to add it manually.
$.validator.setDefaults({
ignore: [],
errorClass: "input-validation-error",
errorElement: "input",
highlight: function (element, errorClass) {
$(element).addClass(errorClass)
},
unhighlight: function (element, errorClass) {
$(element).removeClass(errorClass)
}
});
I found a solution to this based on this post. Basically what you need to do is look for the parent element that the input is wrapped in. Something like this:
$.validator.setDefaults({
ignore: [],
highlight: function (element, errorClass) {
element = $(element);
if (element.parent().hasClass("k-widget")) {
element.parent().addClass('input-validation-error');
} else {
element.addClass('input-validation-error')
}
},
unhighlight: function (element, errorClass) {
element = $(element);
if (element.parent().hasClass("k-widget")) {
element.parent().removeClass('input-validation-error');
} else {
element.removeClass('input-validation-error')
}
}
});
I would advise anyone though to visit the post I've linked to above before taking off down this particular rabbit hole as it introduces another issue, just to be aware of what you're getting into. The excepted answer is really more relevant to this question than the one being asked there.
Related
I've been thinking about this problem for a while, and I can't seem to come up with a reasonable solution. What I would like to do is create getters/setters for a textfield/its value in my view. I realize that the preferred Ext JS way is using a reference within the controller and getting it that way, but that doesn't feel very object-oriented to me. I'd also have to wrap these getters and setters because I want to output a message if the getter returns undefined. What I'd like to do is create my own getters/setters or somehow override the default getters/setters. Here are some ways I was thinking of accomplishing this.
I was thinking I could use the config {}, but that appears to only work for variables I want to define. I then was thinking of using an id somehow, but the community seems split on whether that's a good practice or not. Which leads to my current solution... wrapping. Here's my code:
LoginWindow
Ext.define('MyApp.view.LoginWindow', {
extend: 'Ext.window.Window',
alias: 'widget.loginWindow',
autoShow: true,
closable: false,
border: 0,
plain: true,
allowBlank: false,
title: "Enter your username",
modal: true,
config: {
buttons: [{
text: "Ok"
}],
items: [{
xtype: 'textfield',
fieldLabel: 'Username',
id: 'loginUserInput',
name: 'loginUserInput',
msgTarget: 'under',
validator: function(value) {
if (Ext.isEmpty(value)) {
return "You need to enter a username.";
}
return true;
}
}]
},
constructor: function(config) {
this.callParent(config);
},
getButton: function() {
console.log('here');
}
});
MyController
Ext.define('MyApp.controller.Chat', {
extend: 'Ext.app.Controller',
requires: [
'Views.ChatModule.view.LoginWindow'
],
refs: [{
ref: 'loginWindow',
selector: 'loginWindow',
xtype: 'loginWindow',
autoCreate: true
}, {
ref: 'loginUserInput',
selector: '#loginUserInput'
}],
init: function() {
// The events controller oversees
this.control({
'loginWindow button[text="Ok"]': {
'click': this.onSubmitLoginWindow
}
});
},
getLoginUserInputValue: function() {
var loginUserInput = this.getLoginUserInput();
if (loginUserInput) {
var username = loginUserInput.getValue();
if (username) {
console.log(username);
} else {
console.warn("username is undefined");
}
}
console.warn("loginUserInput is undefined");
},
onSubmitLoginWindow: function(button, event, eOpts) {
this.getLoginUserInputValue();
}
});
This works, and I realize it's a very nit-picky thing, but it just doesn't feel right to have the getter in the controller. I feel like it'd be more object-oriented if it was in the Window. However, if I put it in the Window, I believe my only option is to lean on ids or manually create the textfield in the Window's initComponent--which would involve saving off a reference of the textfield in there, but that seems a bit inefficient... as I would have to make a call to doLayout as well.
Just to reiterate, I'd love to have the getters/setters in the Window, and I'm looking for a quick way to reference it, similar to how the controller references objects. I believe the main answer will be to use ids and making a call to Ext.ComponentQuery.query('#loginUserInput') in the Window, but I'd like to know if there were any better approaches out there... like overriding the auto generated getters/setters or adding a simple getter/setter for an input's value.
Cross-post from the Sencha forums.
Edit
I guess I was a bit unclear with what I want. As a more general statement, instead of jamming all things related to my view in the controller, I'd like to store it all in the view itself, which includes things like getters/setters. One of these getters/setters just so happens to be the loginUserInput getter.
Using a model is an interesting idea, but I feel like that would be a whole lot of overhead for singleton values. I'm basically looking for something like Java's setters/getters in the LoginWindow view... and hopefully something as simple as (or close to) Java's.
The idea of including (encapsulating) it in the view makes the controller a bit cleaner, and if I delete the view, I'm deleting its functions as well, so I don't have to go hunting for the functions in the controller... all I have to worry about is removing the references (which should be minimal).
I think that the "OO" way that you're looking is to work with a Ext.data.Model for your form. If you look at the Ext.form.Basic you have methods to manipulate a model (called record) and also get the object with the values of your view. So you need:
When you create your form, use loadRecord() to bind your form to a Model.
At any time you need, use getValues() to retrieve the values of your form fields.
When submiting your form, use getRecord() and getValues() to sync your record.
Ext.define('MyApp.model.Login',{
fields : [{
name: 'username',
type: 'string'
},{
name: 'password',
type: 'string'
}]
});
Ext.define('MyApp.controller.Login',{
...
refs : [{
selector: 'window form',
ref: 'formPanel'
}],
...
openForm : function() {
//load your form and then bind the new record
var formPanel = this.getFormPanel(), //Ext.form.Panel
form = formPanel.getForm(); //Ext.form.Basic
form.loadRecord(Ext.create('MyApp.model.Login'));
},
save : function() {
//get the values in the view
var form = this.getFormPanel().getForm(),
vals = form.getValues(),
record = form.getRecord();
console.log(vals); //see the object representation of your view here
record.set(vals); //update your model
//do whatever you need with your model
}
...
});
This is an good example when you need to save the form data. In the login I think you can work directly with getValues() without binding it to a Ext.data.Model.
I am not quite certain what problem you are trying to solve to be honest with you.
If you do not like controllers listening to buttons within your window, you can have button handlers witin your view definition fire custom events that controllers can listen on. Use fireEvent method. And by the way initConfig is a recommended way to setup your views. You can break it up into methods if you wish, 'this' reference is available and is the View component being instantiated.
If you need to find inner components within the View there are many methods available from up /down to nextSibling and query .
For Components:
• Ext.getCmp(id)
• Ext.ComponentQuery.query()
• up()
• down()
• nextSibling()
• previousSibling()
• child()
• previousNode()
plus various find.. Methods
EDIT
I think I understood what you mean by getter and setters. Ext forms have the fields finders to make it easy to get and set data to individual fields. See these SO questions: Best way to access adjacent components / fields and EXT.JS getting a list of items from a fieldset
Also like Sergio said there is getRecord getValues and setRecord methods on the form to deal with data binding. Thats it.
EDIT2
The best starting point guide that shows clear and claen MVC patterns as well as form handling. http://docs.sencha.com/extjs/4.1.3/#!/guide/application_architecture
My thoughts are something like this:
...
items: [],
constructor: function(config) {
this.loginUserInput = Ext.create('Ext.form.field.Text', {
fieldLabel: 'Username',
id: 'loginUserInput',
name: 'loginUserInput',
msgTarget: 'under',
validator: function(value) {
if (Ext.isEmpty(value)) {
return "You need to enter a username.";
}
return true;
}
});
this.items.push(this.loginUserInput);
this.callParent(config);
},
getLoginUserInput: function() {
var loginUserInput = this.loginUserInput;
if (!loginUserInput) {
console.warn("LoginWindow::getLoginUserInput: loginUserInput is undefined");
}
return loginUserInput;
}
So instead of letting Ext do its magic, I am now instantiating the object on my own, which then allows me to store away a reference of it, so I can easily access it in my getter. I just wonder if this is creating any sort of performance hit. It doesn't seem like it'd be that much worse... it actually seems like it'd be a bit better because I'm not referencing this object by its ID, and I don't have to go searching for it when I need it.
I have a rallygrid that is configured to display two models: PortfolioItem/Feature and PortfolioItem/Rollup. I want to color them in the grid to differentiate them. I am not garunteed that they will alternate in the grid, or anything like that. I just want to apply a subtle color to the rollups to differentiate them visually.
Can anyone think of an easy way to achieve this?
I have tried:
viewConfig: {
getRowClass: function(record, index, rowParams, store) {
console.log('record',record); // nothing logged in console
console.log('index',index);
return 'colorCodeGrid'; // class never added
}
},
[EDIT]
viewConfig: {
stripeRows: false, // rows are no longer striped
getRowClass: function(record, index, rowParams, store) {
console.log('record',record); // still nothing logged in console
console.log('index',index);
return 'colorCodeGrid'; // class never added
}
},
It is strange to me that the viewConfig does correctly un-stripe the rows, but the getRowClass never gets called. I thought maybe just the viewConfig as a whole was not being used in the case of a rallygrid.
Your approach above with the viewConfig should work- I am going to file a defect on this. The root cause is that the Rally.ui.grid.GridView is blowing away the getRowClass function in its constructor (for internal browser testing purposes- ugghh) rather than checking if there was one supplied and calling that as well.
You can see it the source for the constructor here: https://developer.help.rallydev.com/apps/2.0rc1/doc/source/GridView.html#Rally-ui-grid-GridView
You should be able to work around it by just re-overriding the function before the view is rendered.
[EDIT by asker]
Added the following to the grid, and it worked:
listeners: {
beforerender: function(cmp) {
console.log('beforerender');
console.log('view',cmp);
cmp.view.getRowClass = function(record, index, rowParams, store) {
console.log('record',record); // still nothing logged in console
console.log('index',index);
return 'colorCodeGrid'; // class never added
};
}
},
UPDATE:
I just fixed this in the nightly build, so this should no longer be an issue in public sdk builds beginning with the next public release after 2.0rc2.
I've been during a while working with Ember.js. Now I'm getting a weird behaviour that I cannot fix. Is not the first time I experience it, but in previous occasions I figured it out after making little changes. But now, I really have no idea what's causing the conflict. The issue is occuring in Controllers. I have this ridiculously simple controller, just for testing:
App.AppColleaguesController = Ember.ArrayController.extend
(
{
needs: ['app'],
aNumber: function()
{
return this.get('controllers.app.personId');
}
}
);
Of course, that property is defined on the AppController:
App.AppController = Ember.ArrayController.extend
(
{
loggedIn: false,
personId: -1,
personName: '',
location: '',
logOut: function()
{
if (window.confirm("Do you want log out?"))
{
this.set('loggedIn', false);
this.set('personId', -1);
this.set('personName', '');
this.set('location', '');
this.send('goToLogin');
}
}
}
);
In my template, I'm getting this result:
... This is a number: function () { return
this.get('controllers.app.personId'); } ...
My template is as straightforward as this:
...
This is a number: *{{aNumber}}*
{{debug}}
{{log aNumber}}
...
The debugging statements in my template are showing me this in Firebug console:
...
Transitioned into 'app.colleagues'
function()
...
So, is like the function is literally echoed, not "interpreted". In fact I'm getting this sort of problem in a couple more of controllers, but the rest of them (they are a lot, like 8 or 10 controllers) are working nice. Do you have any idea about the problem? Is my mistake, or maybe an Ember issue?
Thanks a lot in advance! I hope you can help me.
You forgot the .property after the function. This is needed by Ember to indicate that a function is a computed property.
aNumber: function() {
return this.get('controllers.app.personId');
}.property('app.personId')
I have a WinJS application with listviews in which if quickly navigate between pages before the listview is fully loaded, the next page shows the listview with all elements in it bound as "undefined".
So say I have a hub page with a "to do" that is filtered to only show 6 items, and there is a header that navigates to the full "to do" page, when the hub page is displayed but before it is fully loaded I click on the header link to the "to do" page, the app then goes to the "to do" page, but the items show up with all the properties in the tile as "undefined".
I am using IndexedDB as my data store.
My home page code looks like this:
WinJS.UI.Pages.define("/pages/home/home.html", {
ready: function (element, options) {
WinJS.Utilities.query("a").listen("click", function (e) {
e.preventDefault();
WinJS.Navigation.navigate(e.currentTarget.href);
}, false);
viewModel = new HomeViewModel(element);
viewModel.load(); //loads from indexed db
},
//etc...
To Do Page:
WinJS.UI.Pages.define("/pages/ToDo/ToDo.html", {
ready: function (element, options) {
viewModel = new ToDoViewModel(element);
viewModel.load();
},
etc//
I know there isn't much to go off, but any ideas would be appreciated.
Also tips on how to debug something like this would be great.
Update
I narrowed it down to this one line from the Hub Page:
myLib.GetData(todaysDate, function (result) {
that.trendsModel.today = result;
WinJS.Binding.processAll(that.el.querySelector("#dataPanel"), that.trendsModel); //<--Right Here
});
If I remove that, then when I load the second page the data doesn't show as undefined. What is interesting is the data initially shows correctly on the second page and then it changes to "undefined".
Solution
My fix:
myLib.GetData(todaysDate, function (result) {
var element = that.el.querySelector("#dataPanel");
that.trendsModel.today = result;
if(element) {
WinJS.Binding.processAll(element, that.trendsModel);
}
});
At the point when when the callback returns, I am already on the second page. So the selector was not found returning null. If you pass null to processAll it tries to bind the whole page which is why I was able to see the correct data for a second then it changes to undefined...Wow, what a doozy. I guess it makes sense but what a pain to find.
Hope it helps someone in the future :)
Your ToDoViewModel, and HomeViewModel need to be observable. This means they need to mix in from WinJS.Binding.mixin, and for the properties that you pull in asynchronously, they need to call this.notify("propertyName", newVal, oldVal) from the property setter.
Note that you need to have getter/setter properties. e.g.
var bindingBase = WinJS.Class.mix(function() {}, WinJS.Binding.mixin);
WinJS.Namespace.define("YourNamespace", {
ToDoViewModel: WinJS.Class.derive(bindingBase, function constructor() {
}, {
_titleStorage: "",
title: {
get: function() { return this._titleStorage; },
set: function(newValue) {
if(newValue === this._titleStorage) {
return;
}
var old = this._titleStorage;
this._titleStorage = newValue;
this.notify("title", newValue, old);
}
}
}),
});
myLib.GetData(todaysDate, function (result) {
var element = that.el.querySelector("#dataPanel");
that.trendsModel.today = result;
if(element) {
WinJS.Binding.processAll(element, that.trendsModel);
}
});
At the point when when the callback returns, I am already on the second page. So the selector was not found returning null. If you pass null to processAll it tries to bind the whole page which is why I was able to see the correct data for a second then it change to undefined...Wow, what doozy. I guess it makes sense but what a pain to find.
The Sencha store is automatically adding a ajax loader mask when populating the store, but I want to hide it since I have made a more generic mask which is shown every time the app does a ajax request.
How can I hide the store load mask? Tried to look in the documentation, but didnt find any appropriate field/method there:
See attachement:
The property exists: loadingText, which you have set to null.
{
xtype: 'list',
store: 'Store',
loadingText: null, // for ST 2.3.0 set it to false
....
}
Cheers, Oleg
Olegtaranenko: Your solution does remove the loadmask, but setting the
loadingText to 'null' also seems to break the "PullToRefresh" plugin
functionality for a list.
By 'break', I mean that after pulling the arrow down to refresh, the
ui remains in this state, and does not hide the PullToRefresh section
at the top.
Is there a way to hide the additional loadmask, while retaining the
ability to pull to refresh?
For anyone that is reading this in future and is trying to achieve what I have described above, I worked around the issue with PullToRefresh by changing the original Sencha touch 1.1.1 code (line 45346 of sencha-touch-debug-with-comments.js). This is not ideal, but provides a quick workaround.
Original (PullToRefresh breaks)
onBeforeLoad: function() {
if (this.isLoading && this.list.store.getCount() > 0) {
this.list.loadMask.disable();
return false;
}
},
Workaround
onBeforeLoad: function() {
if (this.isLoading && this.list.store.getCount() > 0) {
try{ this.list.loadMask.disable(); }
catch(err) { }
return false;
}
},
Just add on your View
viewConfig: {
loadMask: false
}