Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Выравнивание логики уничтожения моделей #174

Merged
merged 2 commits into from Nov 8, 2013
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 21 additions & 9 deletions src/ns.model.js
Expand Up @@ -451,7 +451,8 @@ ns.Model.prototype.getRequestParams = function() {
* @returns {ns.Model}
*/
ns.Model.get = function(id, params) {
var model = ns.Model.find(id, params);

var model = this._find(id, params);

if (!model) {
var Ctor = _ctors[id];
Expand All @@ -468,18 +469,32 @@ ns.Model.get = function(id, params) {
};

/**
* Returns cached model instance.
* Returns valid cached model instance.
* @param {String} id Model's ID.
* @param {Object} [params] Model's params
* @returns {ns.Model|undefined}
* @returns {ns.Model|null}
*/
ns.Model.find = function(id, params) {
var model = this._find(id, params);
if (model && model.isValid()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А как мне теперь получить любую закешированную модель?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Поговорили голосом.
А как мне теперь получить любую закешированную модель?
С помощью ns.Model.get. Теперь нет существенной разницы между отсутствием экземпляра модели и наличием невалидного экземпляра.

Договорились переименовать метод find в getValid, чтобы название было правдой.

return model;
}
return null;
};

/**
* Returns cached model instance.
* @param {String} id Model's ID.
* @param {Object} [params] Model's params
* @returns {ns.Model|null}
*/
ns.Model._find = function(id, params) {
if (!(id in _infos)) {
throw new Error('[ns.Model] "' + id + '" is not defined');
}

var key = ns.Model.key(id, params);
return _cache[id][key];
return _cache[id][key] || null;
};

/**
Expand All @@ -496,9 +511,6 @@ ns.Model.destroy = function(model) {

var cached = _cache[id][key];
if (cached) {
// remove from cache
delete _cache[id][key];

// notify subscribers about disappearance
model.trigger('ns-model-destroyed');

Expand All @@ -508,8 +520,8 @@ ns.Model.destroy = function(model) {
};

// Проверяем, есть ли модель в кэше и валидна ли она.
ns.Model.isValid = function(id, key) {
var model = ns.Model.get(id, key);
ns.Model.isValid = function(id, params) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вот тут как-то жёстко меняется api. А зачем?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

просто меняется имя переменной =)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

сюда всегда по факту передаются параметры

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ааааа )

var model = ns.Model.get(id, params);
if (!model) { return; } // undefined означает, что кэша нет вообще, а false -- что он инвалидный.

return model.isValid();
Expand Down
62 changes: 36 additions & 26 deletions src/ns.view.js
Expand Up @@ -97,17 +97,16 @@ ns.View.prototype._init = function(id, params, async) {
* Инициализирует модели
*/
ns.View.prototype._initModels = function() {
// Создаёи модели или берем их из кэша, если они уже есть
for (var model_id in this.info.models) {
this._initModel(model_id);
}
};

ns.View.prototype._initModel = function(id) {
if (!this.models) {
this.models = {};
}
this.models[id] = ns.Model.get(id, this.params);

// Создаём модели или берем их из кэша, если они уже есть
for (var id in this.info.models) {
if (!this.models[id]) {
this.models[id] = ns.Model.get(id, this.params);
}
}
};

// --------------------------------------------------------------------------------------------------------------- //
Expand Down Expand Up @@ -653,8 +652,7 @@ ns.View.prototype._bindModels = function() {
var model = models[model_id];

model.on('ns-model-destroyed', function() {
delete that.models[this.id];
that._initModel(this.id);
that.invalidate();
});

var jpaths = subviews[model_id];
Expand Down Expand Up @@ -909,7 +907,7 @@ ns.View.prototype.isSubviewsOk = function() {
* Возвращает true, если блок валиден.
* @return {Boolean}
*/
ns.View.prototype.isValid = function() {
ns.View.prototype.isValid = ns.View.prototype.isValidSelf = function() {
return this.isOk() && this.isSubviewsOk() && this.isModelsValidWithVersions();
};

Expand Down Expand Up @@ -974,6 +972,32 @@ ns.View.prototype._apply = function(callback) {
* @return {*}
*/
ns.View.prototype._getRequestViews = function(updated, pageLayout, params) {

// При необходимости добавим текущий вид в список "запрашиваемых"
this._tryPushToRequest(updated);

// Если views еще не определены (первая отрисовка)
if (!this.views) {
// FIXME: Почему бы это в конструкторе не делать?
this.views = {};
// Создаем подблоки
for (var view_id in pageLayout) {
this._addView(view_id, params, pageLayout[view_id].type);
}
}

this._apply(function(view, id) {
view._getRequestViews(updated, pageLayout[id].views, params);
});

return updated;
};

/**
* Добавляет вид в соответствующий список "запрашиваемых" видов в случае,
* если запрос необходим
*/
ns.View.prototype._tryPushToRequest = function(updated) {
/**
* Флаг, означающий, что view грузится асинхронно.
* @type {Boolean}
Expand All @@ -994,25 +1018,11 @@ ns.View.prototype._getRequestViews = function(updated, pageLayout, params) {
// прекращаем обработку
return updated;
}
} else if (!this.isValid()) {
} else if (!this.isValidSelf()) {
// если обычный блок не валиден
updated.sync.push(this);
}

// Если views еще не определены (первая отрисовка)
if (!this.views) {
// FIXME: Почему бы это в конструкторе не делать?
this.views = {};
// Создаем подблоки
for (var view_id in pageLayout) {
this._addView(view_id, params, pageLayout[view_id].type);
}
}

this._apply(function(view, id) {
view._getRequestViews(updated, pageLayout[id].views, params);
});

return updated;
};

Expand Down
38 changes: 2 additions & 36 deletions src/ns.viewCollection.js
Expand Up @@ -58,8 +58,7 @@ ns.ViewCollection.prototype._bindModels = function() {
var model = models[model_id];

model.on('ns-model-destroyed', function() {
delete that.models[this.id];
that._initModel(this.id);
that.invalidate();
});

model.on('ns-model-changed', function(e, o) {
Expand All @@ -75,12 +74,6 @@ ns.ViewCollection.prototype.isValid = function() {
return this.isValidSelf() && this.isValidDesc();
};

/**
* Check self validity (except items).
* @returns {Boolean}
*/
ns.ViewCollection.prototype.isValidSelf = ns.View.prototype.isValid;

ns.ViewCollection.prototype.isValidDesc = function() {
for (var key in this.views) {
if (!this.views[key].isValid()) {
Expand Down Expand Up @@ -159,34 +152,7 @@ ns.ViewCollection.prototype._apply = function(callback) {
}
};

ns.ViewCollection.prototype._getRequestViews = function(updated) {
/**
* Флаг, означающий, что view грузится асинхронно.
* @type {Boolean}
*/
this.asyncState = false;

if (this.async) {
var hasValidModels = this.isModelsValid();
var hasValidStatus = this.isOk();
if (hasValidModels && !hasValidStatus) {
// если асинхронный блок имеет валидные модели, но невалидный статус - рисуем его синхронно
updated.sync.push(this);

} else if (!hasValidModels) {
this.asyncState = true;
// если асинхронный блок имеет невалидные модели, то его не надо рисовать
updated.async.push(this);
// прекращаем обработку
return updated;
}
} else if (!this.isValidSelf()) {
// если обычный блок не валиден
updated.sync.push(this);
}

return updated;
};
ns.ViewCollection.prototype._getRequestViews = ns.View.prototype._tryPushToRequest;

ns.ViewCollection.prototype._getUpdateTree = function(tree, layout, params) {
var decl;
Expand Down
7 changes: 4 additions & 3 deletions test/spec/ns.model.js
Expand Up @@ -138,12 +138,13 @@ describe('ns.Model', function() {

describe('ns.Model.find():', function() {

it('should return undefined if model doesn\'t exists', function() {
expect(ns.Model.find('m1')).to.be(undefined);
it('should return null if model doesn\'t exists', function() {
expect(ns.Model.find('m1')).to.be(null);
});

it('should return model if exists', function() {
it('should return valid model if exists', function() {
var m = ns.Model.get('m1');
m.setData({foo: 'bar'});
expect(ns.Model.find('m1')).to.be.ok(m);
});

Expand Down
9 changes: 8 additions & 1 deletion test/spec/ns.viewCollection.js
Expand Up @@ -437,8 +437,10 @@ describe('ns.ViewCollection', function() {
.start()
.done(function() {
ns.Model.destroy(ns.Model.get('mCollection'));
ns.Model.destroy(ns.Model.get('mItem', {id: '0'}));
ns.Model.destroy(ns.Model.get('mItem', {id: '1'}));

ns.Model.get('mCollection').setData({data: [{id: 3}]});
ns.Model.get('mCollection').setData({data: [{id: '2'}]});

new ns.Update(this.APP, layout, {})
.start()
Expand All @@ -452,6 +454,11 @@ describe('ns.ViewCollection', function() {
delete this.APP;
});

it('shouldn`t find destroyed models', function() {
expect(ns.Model.find('mItem', {id: '0'})).not.to.be.ok();
expect(ns.Model.find('mItem', {id: '1'})).not.to.be.ok();
});

it('should have 1 node for view vItem', function() {
expect(this.APP.node.querySelectorAll('.ns-view-vItem').length).to.be(1);
});
Expand Down