Thanks for the solution :D About an hour or so ago, I managed to find the solution on my own, which is quite similar to yours (below is the fully working widget with some pretty nifty validation on top of it, if anybody needs another grid example):
- (function ($, can, moment) {
- var DosareDauna = can.Model.extend({
- findAll: "/conta/Plati/GetDosareForSelectie"
- }, {
- setValoareDeExecutat: function (valoare, success, error) {
- if (isNaN(valoare)) {
- error('Sumele trebuie formate din cifre!');
- return valoare;
- }
- else {
- var valoareParsata = parseFloat(valoare);
- if (valoareParsata > 0) {
- success(valoareParsata);
- }
- else
- error('Suma executata pt un dosar trebuie sa fie mai mare decat 0!');
- return valoareParsata;
- }
- }
- });
- can.Component.extend({
- tag: "executadosare",
- //template: can.view("selecteazaDosare"),
- init: function () {
- var self = this.scope;
- var promise = DosareDauna.findAll({ id: self.attr('selectieid') });
- promise.then(function (dosare) {
- dosare.forEach(function (element, index, list) {
- element.attr('ValoareDeExecutat', element.attr('SumaMaxima'))
- element.attr('IsSelected', false);
- element.attr('EsteFinal', false);
- element.bind("error", function (ev, attr, error) {
- if (self.attr('Errors.Dosar') === undefined)
- self.attr('Errors').attr('Dosar', error);
- });
- element.bind("success", function (ev, attr, success) {
- if (self.attr('Errors.Dosar') !== undefined)
- self.attr('Errors').removeAttr('Dosar');
- });
- });
- self.attr('Count', dosare.length);
- self.attr('ToateDosarele').replace(dosare);
- self.attr('sumaMaxima', dosare.sumaMaxima);
- });
- },
- scope: {
- Errors: {},
- HasError:function(){
- var self = this.attr('Errors');
- console.log(self.attr());
- if (self.attr('Selectie') === undefined && self.attr('Suma') === undefined && self.attr('Dosar') === undefined)
- return false;
- else
- return true;
- },
- Count: Infinity,
- Offset: 0,
- Limit: 5,
- Prev: function () {
- this.attr('Offset', this.Offset - this.Limit)
- },
- Next: function () {
- this.attr('Offset', this.Offset + this.Limit);
- },
- CanNext: function () {
- return this.attr('Offset') < this.attr('Count') - this.attr('Limit');
- },
- CanPrev: function () {
- return this.attr('Offset') > 0;
- },
- ToateDosarele: [],
- Dosare: function () {
- var self = this;
- var dosarePaginate = [];
- self.attr('ToateDosarele').forEach(function (element, index, list) {
- if (index >= self.attr('Offset') && index < (self.attr('Offset') + self.attr('Limit'))) {
- dosarePaginate.push(element);
- }
- });
- return dosarePaginate;
- },
- DosareSelectate: function () {
- var self = this;
- var selectate = new can.List([]);
- var sumaTotala = 0;
- self.attr('ToateDosarele').forEach(function (element, index, list) {
- if (element.attr('IsSelected') === true) {
- selectate.push(element);
- sumaTotala = sumaTotala + element.attr('ValoareDeExecutat');
- }
- });
- self.attr('Suma', sumaTotala);
- return selectate;
- },
- Suma: 0,
- SelectAll: function () {
- var self = this;
- self.attr('ToateDosarele').forEach(function (element, index, list) {
- element.attr('IsSelected', true);
- });
- },
- FinalAll: function () {
- var self = this;
- self.DosareSelectate().forEach(function (element, index, list) {
- element.attr('EsteFinal', true);
- });
- }
- },
- events: {
- '#submitExecutie click': function (el, ev) {
- if (this.validate() === true)
- ev.preventDefault();
- },
- '{scope} Suma': 'validate',
- validate: function () {
- var self = this.scope;
- var hasErrors = false;
- if (self.attr('Suma') <= 0) {
- if (self.attr('Errors.Suma') === undefined)
- self.attr('Errors').attr('Suma', 'Suma trebuie sa fie mai mare decat 0!');
- hasErrors = true;
- }
- else
- if (self.attr('sumaMaxima') < self.attr('Suma')) {
- if (self.attr('Errors.Suma') === undefined)
- self.attr('Errors').attr('Suma', 'Suma trebuie sa fie mai mica decat ' + self.attr('sumaMaxima') + '!');
- hasErrors = true;
- }
- else {
- if (self.attr('Errors.Suma') !== undefined)
- self.attr('Errors').removeAttr('Suma');
- }
- if (self.DosareSelectate().length === 0) {
- if (self.attr('Errors.Selectie') === undefined)
- self.attr('Errors').attr('Selectie', 'Trebuie selectate dosare pt executie!');
- hasErrors = true;
- }
- else {
- if (self.attr('Errors.Selectie') !== undefined)
- self.attr('Errors').removeAttr('Selectie');
- var areNumereAiurea = false;
- self.DosareSelectate().forEach(function (element, index, list) {
- if (isNaN(element.attr('ValoareDeExecutat'))) {
- areNumereAiurea = true;
- }
- });
- if (!areNumereAiurea) {
- if (self.attr('Errors.Dosar') !== undefined)
- self.attr('Errors').removeAttr('Dosar');
- }
- else
- if (self.attr('Errors.Dosar') === undefined)
- self.attr('Errors').attr('Dosar', 'Sumele trebuie formate din cifre!');
- }
- return hasErrors;
- }
- },
- helpers: {
- // {{date-format 'unix offset, date string or timestamp' 'mm-dd-yy'}}
- "date-format": function (time) {
- if (can.isFunction(time)) time = time();
- return moment(time).format('YYYY MM DD');
- }
- }
- });
- }(jQuery, can, moment));
Things I've learned:
1. When passing parameters through a custom Component tag, always use lowercase letters for the scope property.
2. Functions automatically become computes IF they are referenced in the Mustache view, otherwise if they're simply called by the code, they must be enclosed in a can.compute(..)
3. When setting if else clauses for things like disabled="disabled", don't leave any whitespace.
At this point, in order to make the code better, I'd push the validation inside the object that is returned by the deferred, and set it up so that it can push errors in the widget that it is passed.
In any case, thanks for the help, air_hadoken :D