Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
waitFor array
Browse files Browse the repository at this point in the history
RickButler committed Oct 13, 2018

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 283b599 commit 9322ff3
Showing 3 changed files with 40 additions and 29 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -580,7 +580,7 @@ subview declarations consist of:
* selector {String} Selector that describes the element within the view that should hold the subview.
* hook {String} Alternate method for specifying a container element using its `data-hook` attribute. Equivalent to `selector: '[data-hook=some-hook]'`.
* constructor {ViewConstructor} Any [view conventions compliant](http://ampersandjs.com/learn/view-conventions) view constructor. It will be initialized with `{el: [Element grabbed from selector], parent: [reference to parent view instance]}`. So if you don't need to do any custom setup, you can just provide the constructor.
* waitFor {String} String specifying they "key-path" (i.e. 'model.property') of the view that must be "truthy" before it should consider the subview ready.
* waitFor {String|Array} String or Array of Strings specifying the "key-path" (i.e. 'model.property') of the view that must be "truthy" before it should consider the subview ready.
* prepareView {Function} Function that will be called once any `waitFor` condition is met. It will be called with the `this` context of the parent view and with the element that matches the selector as the argument. It should return an instantiated view instance.

### delegateEvents `view.delegateEvents([events])`
44 changes: 23 additions & 21 deletions ampersand-view.js
Original file line number Diff line number Diff line change
@@ -3,26 +3,24 @@ var State = require('ampersand-state');
var CollectionView = require('ampersand-collection-view');
var domify = require('domify');
var uniqueId = require("lodash/uniqueId");
var pick = require("lodash/pick");
var assign = require("lodash/assign");
var forEach = require("lodash/forEach");
var result = require("lodash/result");
var last = require("lodash/last");
var isString = require("lodash/isString");
var bind = require("lodash/bind");
var flatten = require("lodash/flatten");
var invokeMap = require("lodash/invokeMap");
var events = require('events-mixin');
var matches = require('matches-selector');
var bindings = require('ampersand-dom-bindings');
var getPath = require('lodash/get');
var castArray = require('lodash/castArray');

function View(attrs) {
this.cid = uniqueId('view');
attrs || (attrs = {});
var parent = attrs.parent;
delete attrs.parent;
BaseState.call(this, attrs, {init: false, parent: parent});
BaseState.call(this, attrs, { init: false, parent: parent });
this.on('change:el', this._handleElementChange, this);
this._upsertBindings();
this.template = attrs.template || this.template;
@@ -75,7 +73,7 @@ var BaseState = State.extend({
},
rendered: {
deps: ['_rendered'],
fn: function() {
fn: function () {
if (this._rendered) {
this.trigger('render', this);
return true;
@@ -141,7 +139,7 @@ assign(View.prototype, {

// Initialize is an empty function by default. Override it with your own
// initialization logic.
initialize: function () {},
initialize: function () { },

// **render** is the core function that your view can override. Its job is
// to populate its element (`this.el`), with the appropriate HTML.
@@ -267,12 +265,16 @@ assign(View.prototype, {
subview.selector = subview.container;
}
var opts = this._parseSubviewOpts(subview);
var hasViewPath = function (path) {
return !!getPath(this, path);
};


function action() {
var el, subview;
// if not rendered or we can't find our element, stop here.
if (!this.el || !(el = this.query(opts.selector))) return;
if (!opts.waitFor || getPath(this, opts.waitFor)) {
if (!opts.waitFor.length || opts.waitFor.every(hasViewPath, this)) {
subview = this[name] = opts.prepareView.call(this, el);
if (!subview.el) {
this.renderSubview(subview, el);
@@ -299,7 +301,7 @@ assign(View.prototype, {
var self = this;
var opts = {
selector: subview.selector || '[data-hook="' + subview.hook + '"]',
waitFor: subview.waitFor || '',
waitFor: subview.waitFor ? castArray(subview.waitFor) : [],
prepareView: subview.prepareView || function () {
return new subview.constructor({
parent: self
@@ -383,13 +385,13 @@ assign(View.prototype, {
return this.registerSubview(collectionView);
},

_setRender: function(obj) {
_setRender: function (obj) {
Object.defineProperty(obj, 'render', {
get: function() {
get: function () {
return this._render;
},
set: function(fn) {
this._render = function() {
set: function (fn) {
this._render = function () {
this._upsertBindings();
fn.apply(this, arguments);
this._rendered = true;
@@ -399,13 +401,13 @@ assign(View.prototype, {
});
},

_setRemove: function(obj) {
_setRemove: function (obj) {
Object.defineProperty(obj, 'remove', {
get: function() {
get: function () {
return this._remove;
},
set: function(fn) {
this._remove = function() {
set: function (fn) {
this._remove = function () {
fn.apply(this, arguments);
this._rendered = false;
this._downsertBindings();
@@ -415,18 +417,18 @@ assign(View.prototype, {
});
},

_downsertBindings: function() {
_downsertBindings: function () {
var parsedBindings = this._parsedBindings;
if (!this.bindingsSet) return;
if (this._subviews){
invokeMap(flatten(this._subviews), 'remove');
this._subviews = [];
if (this._subviews) {
invokeMap(flatten(this._subviews), 'remove');
this._subviews = [];
}
this.stopListening();
this.bindingsSet = false;
},

_upsertBindings: function(attrs) {
_upsertBindings: function (attrs) {
attrs = attrs || this;
if (this.bindingsSet) return;
this._parsedBindings = bindings(this.bindings, this);
23 changes: 16 additions & 7 deletions test/main.js
Original file line number Diff line number Diff line change
@@ -864,10 +864,11 @@ test('make sure subviews dont fire until their `waitFor` is done', function (t)
});

var View = AmpersandView.extend({
template: '<div><span class="container"></span><span data-hook="sub"></span></div>',
template: '<div><span class="container"></span><span data-hook="sub"></span><span data-hook="subthree"></span></div>',
autoRender: true,
props: {
model2: 'state'
model2: 'state',
subThreeReady: 'boolean'
},
subviews: {
sub1: {
@@ -879,22 +880,30 @@ test('make sure subviews dont fire until their `waitFor` is done', function (t)
waitFor: 'model2',
hook: 'sub',
constructor: Sub
},
sub3: {
waitFor: ['model', 'model2','subThreeReady'],
hook: 'subthree',
constructor: Sub
}
}
});
var view = new View();
t.equal(view._events.change.length, 2);
t.equal(view.el.outerHTML, '<div><span class="container"></span><span data-hook="sub"></span></div>');
t.equal(view._events.change.length, 3, 'three change events change events on instantiation');
t.equal(view.el.outerHTML, '<div><span class="container"></span><span data-hook="sub"></span><span data-hook="subthree"></span></div>', 'the subviews should be empty');
view.model = new Model();
t.equal(view._events.change.length, 1);
t.equal(view.el.outerHTML, '<div><span class="container"><span>yes</span></span><span data-hook="sub"></span></div>');
t.equal(view._events.change.length, 2, 'triggers change');
t.equal(view.el.outerHTML, '<div><span class="container"><span>yes</span></span><span data-hook="sub"></span><span data-hook="subthree"></span></div>', 'the subview sub1 should have rendered');
view.model2 = new Model();
t.equal(view.el.outerHTML, '<div><span class="container"><span>yes</span></span><span data-hook="sub"><span>yes</span></span></div>');
t.equal(view.el.outerHTML, '<div><span class="container"><span>yes</span></span><span data-hook="sub"><span>yes</span></span><span data-hook="subthree"></span></div>','the subviews sub2 should have rendered');
view.subThreeReady = true;
t.equal(view.el.outerHTML, '<div><span class="container"><span>yes</span></span><span data-hook="sub"><span>yes</span></span><span data-hook="subthree"><span>yes</span></span></div>','the subviews sub3 should have rendered');
t.notOk(view._events.change);

t.end();
});


test('make sure template can return a dom node', function (t) {
var Sub = AmpersandView.extend({
template: function () {

0 comments on commit 9322ff3

Please sign in to comment.