Skip to content

Commit 31bd85c

Browse files
committed
[FEATURE] if helper inline form
1 parent f4ccf17 commit 31bd85c

File tree

5 files changed

+246
-5
lines changed

5 files changed

+246
-5
lines changed

FEATURES.md

+8
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,11 @@ for a detailed explanation.
8686

8787
Enables HTMLBars compiler to interpret `<x-foo></x-foo>` as a component
8888
invocation (instead of a standard HTML5 style element).
89+
90+
* `ember-htmlbars-inline-if-helper`
91+
92+
Enables the use of the if helper in inline form. The truthy
93+
and falsy values are passed as params, instead of using the block form.
94+
95+
Added in [#9718](https://github.com/emberjs/ember.js/pull/9718).
96+

features.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"ember-testing-pause-test": true,
1919
"ember-htmlbars": null,
2020
"ember-htmlbars-block-params": null,
21-
"ember-htmlbars-component-generation": null
21+
"ember-htmlbars-component-generation": null,
22+
"ember-htmlbars-inline-if-helper": null
2223
},
2324
"debugStatements": [
2425
"Ember.warn",

packages/ember-htmlbars/lib/helpers/if_unless.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { bind } from "ember-htmlbars/helpers/binding";
88

99
import { get } from "ember-metal/property_get";
1010
import { isArray } from "ember-metal/utils";
11+
import ConditionalStream from "ember-views/streams/conditional_stream";
1112

1213
function shouldDisplayIfHelperContent(result) {
1314
var truthy = result && get(result, 'isTruthy');
@@ -89,13 +90,21 @@ function unboundIfHelper(params, hash, options, env) {
8990
@return {String} HTML string
9091
*/
9192
function ifHelper(params, hash, options, env) {
92-
Ember.assert("You must pass exactly one argument to the if helper", params.length === 1);
93-
Ember.assert("You must pass a block to the if helper", !!options.render);
94-
95-
options.helperName = options.helperName || ('if ');
93+
Ember.assert("If helper in block form expect exactly one argument", !options.render || params.length === 1);
94+
if (Ember.FEATURES.isEnabled('ember-htmlbars-inline-if-helper')) {
95+
if (!options.render) {
96+
Ember.assert("If helper in inline form expects between two and three arguments", params.length === 2 || params.length === 3);
97+
var condition = params[0];
98+
var truthy = params[1];
99+
var falsy = params[2];
100+
return new ConditionalStream(condition, truthy, falsy);
101+
}
102+
}
96103

97104
options.inverse = options.inverse || function(){ return ''; };
98105

106+
options.helperName = options.helperName || ('if ');
107+
99108
if (env.data.isUnbound) {
100109
return env.helpers.unboundIf.helperFunction.call(this, params, hash, options, env);
101110
} else {

packages/ember-htmlbars/tests/helpers/if_unless_test.js

+171
Original file line numberDiff line numberDiff line change
@@ -665,3 +665,174 @@ test('edge case: rerender appearance of inner virtual view', function() {
665665

666666
equal(Ember.$('#qunit-fixture').text(), 'test');
667667
});
668+
669+
if (Ember.FEATURES.isEnabled('ember-htmlbars-inline-if-helper')) {
670+
test("`if` helper with inline form: renders the second argument when conditional is truthy", function() {
671+
view = EmberView.create({
672+
conditional: true,
673+
template: compile('{{if view.conditional "truthy" "falsy"}}')
674+
});
675+
676+
appendView(view);
677+
678+
equal(view.$().text(), 'truthy');
679+
});
680+
681+
test("`if` helper with inline form: renders the third argument when conditional is falsy", function() {
682+
view = EmberView.create({
683+
conditional: false,
684+
template: compile('{{if view.conditional "truthy" "falsy"}}')
685+
});
686+
687+
appendView(view);
688+
689+
equal(view.$().text(), 'falsy');
690+
});
691+
692+
test("`if` helper with inline form: can omit the falsy argument", function() {
693+
view = EmberView.create({
694+
conditional: true,
695+
template: compile('{{if view.conditional "truthy"}}')
696+
});
697+
698+
appendView(view);
699+
700+
equal(view.$().text(), 'truthy');
701+
});
702+
703+
test("`if` helper with inline form: can omit the falsy argument and renders nothing when conditional is falsy", function() {
704+
view = EmberView.create({
705+
conditional: false,
706+
template: compile('{{if view.conditional "truthy"}}')
707+
});
708+
709+
appendView(view);
710+
711+
equal(view.$().text(), '');
712+
});
713+
714+
test("`if` helper with inline form: truthy and falsy arguments are changed if conditional changes", function() {
715+
view = EmberView.create({
716+
conditional: true,
717+
template: compile('{{if view.conditional "truthy" "falsy"}}')
718+
});
719+
720+
appendView(view);
721+
722+
equal(view.$().text(), 'truthy');
723+
724+
run(function() {
725+
view.set('conditional', false);
726+
});
727+
728+
equal(view.$().text(), 'falsy');
729+
});
730+
731+
test("`if` helper with inline form: can use truthy param as binding", function() {
732+
view = EmberView.create({
733+
truthy: 'ok',
734+
conditional: true,
735+
template: compile('{{if view.conditional view.truthy}}')
736+
});
737+
738+
appendView(view);
739+
740+
equal(view.$().text(), 'ok');
741+
742+
run(function() {
743+
view.set('truthy', 'yes');
744+
});
745+
746+
equal(view.$().text(), 'yes');
747+
});
748+
749+
test("`if` helper with inline form: can use falsy param as binding", function() {
750+
view = EmberView.create({
751+
truthy: 'ok',
752+
falsy: 'boom',
753+
conditional: false,
754+
template: compile('{{if view.conditional view.truthy view.falsy}}')
755+
});
756+
757+
appendView(view);
758+
759+
equal(view.$().text(), 'boom');
760+
761+
run(function() {
762+
view.set('falsy', 'no');
763+
});
764+
765+
equal(view.$().text(), 'no');
766+
});
767+
768+
test("`if` helper with inline form: raises when using more than three arguments", function() {
769+
view = EmberView.create({
770+
conditional: true,
771+
template: compile('{{if one two three four}}')
772+
});
773+
774+
expectAssertion(function() {
775+
appendView(view);
776+
}, 'If helper in inline form expects between two and three arguments');
777+
});
778+
779+
test("`if` helper with inline form: raises when using less than two arguments", function() {
780+
view = EmberView.create({
781+
conditional: true,
782+
template: compile('{{if one}}')
783+
});
784+
785+
expectAssertion(function() {
786+
appendView(view);
787+
}, 'If helper in inline form expects between two and three arguments');
788+
});
789+
790+
test("`if` helper with inline form: works when used in a sub expression", function() {
791+
view = EmberView.create({
792+
conditional: true,
793+
innerConditional: true,
794+
template: compile('{{if view.conditional (if view.innerConditional "truthy" )}}')
795+
});
796+
797+
appendView(view);
798+
799+
equal(view.$().text(), 'truthy');
800+
});
801+
802+
test("`if` helper with inline form: updates if condition changes in a sub expression", function() {
803+
view = EmberView.create({
804+
conditional: true,
805+
innerConditional: true,
806+
template: compile('{{if view.conditional (if view.innerConditional "innerTruthy" "innerFalsy")}}')
807+
});
808+
809+
appendView(view);
810+
811+
equal(view.$().text(), 'innerTruthy');
812+
813+
run(function() {
814+
view.set('innerConditional', false);
815+
});
816+
817+
equal(view.$().text(), 'innerFalsy');
818+
});
819+
820+
test("`if` helper with inline form: can use truthy param as binding in a sub expression", function() {
821+
view = EmberView.create({
822+
conditional: true,
823+
innerConditional: true,
824+
innerTruthy: "innerTruthy",
825+
template: compile('{{if view.conditional (if view.innerConditional view.innerTruthy)}}')
826+
});
827+
828+
appendView(view);
829+
830+
equal(view.$().text(), 'innerTruthy');
831+
832+
run(function() {
833+
view.set('innerTruthy', 'innerOk');
834+
});
835+
836+
equal(view.$().text(), 'innerOk');
837+
});
838+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import Stream from "ember-metal/streams/stream";
2+
import { read } from "ember-metal/streams/read";
3+
import { create as o_create } from "ember-metal/platform";
4+
5+
function ConditionalStream(test, consequent, alternate) {
6+
this._super(conditionalValueFn);
7+
this.oldTest = undefined;
8+
this.test = test;
9+
this.consequent = consequent;
10+
this.alternate = alternate;
11+
12+
if (test && test.isStream) {
13+
test.subscribe(this.notify, this);
14+
}
15+
}
16+
17+
ConditionalStream.prototype = o_create(Stream.prototype);
18+
ConditionalStream.prototype._super = Stream;
19+
20+
ConditionalStream.prototype._unsubscribe = function(value) {
21+
if (value && value.isStream) {
22+
value.unsubscribe(this.notify, this);
23+
}
24+
};
25+
26+
ConditionalStream.prototype._subscribe = function(value) {
27+
if (value && value.isStream) {
28+
value.subscribe(this.notify, this);
29+
}
30+
};
31+
32+
function conditionalValueFn() {
33+
var test = !!read(this.test);
34+
35+
if (test !== this.oldTest) {
36+
if (this.oldTest) {
37+
this._unsubscribe(this.consequent);
38+
} else {
39+
this._unsubscribe(this.alternate);
40+
}
41+
if (test) {
42+
this._subscribe(this.consequent);
43+
} else {
44+
this._subscribe(this.alternate);
45+
}
46+
this.oldTest = test;
47+
}
48+
49+
return test ? read(this.consequent) : read(this.alternate);
50+
}
51+
52+
export default ConditionalStream;

0 commit comments

Comments
 (0)