diff --git a/packages/ember-routing-views/lib/components/link-to.js b/packages/ember-routing-views/lib/components/link-to.js index ad0fad23376..bb497dc196f 100644 --- a/packages/ember-routing-views/lib/components/link-to.js +++ b/packages/ember-routing-views/lib/components/link-to.js @@ -623,14 +623,16 @@ let LinkComponent = EmberComponent.extend({ _invoke(event) { if (!isSimpleClick(event)) { return true; } - if (this.attrs.preventDefault !== false) { - let targetAttribute = this.attrs.target; + let preventDefault = get(this, 'preventDefault'); + let targetAttribute = get(this, 'target'); + + if (preventDefault !== false) { if (!targetAttribute || targetAttribute === '_self') { event.preventDefault(); } } - if (this.attrs.bubbles === false) { event.stopPropagation(); } + if (get(this, 'bubbles') === false) { event.stopPropagation(); } if (get(this, '_isDisabled')) { return false; } @@ -639,8 +641,7 @@ let LinkComponent = EmberComponent.extend({ return false; } - let targetAttribute2 = this.attrs.target; - if (targetAttribute2 && targetAttribute2 !== '_self') { + if (targetAttribute && targetAttribute !== '_self') { return false; } @@ -648,7 +649,7 @@ let LinkComponent = EmberComponent.extend({ let qualifiedRouteName = get(this, 'qualifiedRouteName'); let models = get(this, 'models'); let queryParamValues = get(this, 'queryParams.values'); - let shouldReplace = get(this, 'attrs.replace'); + let shouldReplace = get(this, 'replace'); routing.transitionTo(qualifiedRouteName, models, queryParamValues, shouldReplace); }, @@ -656,7 +657,7 @@ let LinkComponent = EmberComponent.extend({ queryParams: null, qualifiedRouteName: computed('targetRouteName', '_routing.currentState', function computeLinkToComponentQualifiedRouteName() { - let params = this.attrs.params.slice(); + let params = get(this, 'params').slice(); let lastParam = params[params.length - 1]; if (lastParam && lastParam.isQueryParams) { params.pop(); @@ -738,15 +739,14 @@ let LinkComponent = EmberComponent.extend({ willRender() { let queryParams; - let attrs = this.attrs; - // Do not mutate params in place - let params = attrs.params.slice(); + let params = get(this, 'params').slice(); assert('You must provide one or more parameters to the link-to component.', params.length); - if (attrs.disabledWhen) { - this.set('disabled', attrs.disabledWhen); + let disabledWhen = get(this, 'disabledWhen'); + if (disabledWhen) { + this.set('disabled', disabledWhen); } // Process the positional arguments, in order. diff --git a/packages/ember/tests/helpers/link_to_test.js b/packages/ember/tests/helpers/link_to_test.js index e5435a64ece..986c64bfeda 100644 --- a/packages/ember/tests/helpers/link_to_test.js +++ b/packages/ember/tests/helpers/link_to_test.js @@ -189,6 +189,62 @@ QUnit.test('The {{link-to}} helper supports URL replacement', function() { equal(replaceCount, 1, 'replaceURL should be called once'); }); +QUnit.test('The {{link-to}} helper supports URL replacement via replace=boundTruthyThing', function() { + Ember.TEMPLATES.index = compile('

Home

{{#link-to \'about\' id=\'about-link\' replace=boundTruthyThing}}About{{/link-to}}'); + + App.IndexController = Controller.extend({ + boundTruthyThing: true + }); + + Router.map(function() { + this.route('about'); + }); + + bootApplication(); + + run(function() { + router.handleURL('/'); + }); + + equal(updateCount, 0, 'precond: setURL has not been called'); + equal(replaceCount, 0, 'precond: replaceURL has not been called'); + + run(function() { + jQuery('#about-link', '#qunit-fixture').click(); + }); + + equal(updateCount, 0, 'setURL should not be called'); + equal(replaceCount, 1, 'replaceURL should be called once'); +}); + +QUnit.test('The {{link-to}} helper supports setting replace=boundFalseyThing', function() { + Ember.TEMPLATES.index = compile('

Home

{{#link-to \'about\' id=\'about-link\' replace=boundFalseyThing}}About{{/link-to}}'); + + App.IndexController = Controller.extend({ + boundFalseyThing: false + }); + + Router.map(function() { + this.route('about'); + }); + + bootApplication(); + + run(function() { + router.handleURL('/'); + }); + + equal(updateCount, 0, 'precond: setURL has not been called'); + equal(replaceCount, 0, 'precond: replaceURL has not been called'); + + run(function() { + jQuery('#about-link', '#qunit-fixture').click(); + }); + + equal(updateCount, 1, 'setURL should be called'); + equal(replaceCount, 0, 'replaceURL should not be called'); +}); + QUnit.test('the {{link-to}} helper doesn\'t add an href when the tagName isn\'t \'a\'', function() { Ember.TEMPLATES.index = compile('{{#link-to \'about\' id=\'about-link\' tagName=\'div\'}}About{{/link-to}}'); @@ -207,9 +263,14 @@ QUnit.test('the {{link-to}} helper doesn\'t add an href when the tagName isn\'t QUnit.test('the {{link-to}} applies a \'disabled\' class when disabled', function () { - Ember.TEMPLATES.index = compile('{{#link-to "about" id="about-link" disabledWhen="shouldDisable"}}About{{/link-to}}'); + Ember.TEMPLATES.index = compile(` + {{#link-to "about" id="about-link-static" disabledWhen="shouldDisable"}}About{{/link-to}} + {{#link-to "about" id="about-link-dynamic" disabledWhen=dynamicDisabledWhen}}About{{/link-to}} + `); + App.IndexController = Controller.extend({ - shouldDisable: true + shouldDisable: true, + dynamicDisabledWhen: 'shouldDisable' }); Router.map(function() { @@ -222,7 +283,8 @@ QUnit.test('the {{link-to}} applies a \'disabled\' class when disabled', functio router.handleURL('/'); }); - equal(jQuery('#about-link.disabled', '#qunit-fixture').length, 1, 'The link is disabled when its disabledWhen is true'); + equal(jQuery('#about-link-static.disabled', '#qunit-fixture').length, 1, 'The static link is disabled when its disabledWhen is true'); + equal(jQuery('#about-link-dynamic.disabled', '#qunit-fixture').length, 1, 'The dynamic link is disabled when its disabledWhen is true'); }); QUnit.test('the {{link-to}} doesn\'t apply a \'disabled\' class if disabledWhen is not provided', function () { @@ -605,6 +667,45 @@ QUnit.test('The {{link-to}} helper supports bubbles=false', function() { equal(hidden, 0, 'The link didn\'t bubble'); }); +QUnit.test('The {{link-to}} helper supports bubbles=boundFalseyThing', function() { + Ember.TEMPLATES.about = compile('
{{#link-to \'about.contact\' id=\'about-contact\' bubbles=boundFalseyThing}}About{{/link-to}}
{{outlet}}'); + Ember.TEMPLATES['about/contact'] = compile('

Contact

'); + + App.AboutController = Controller.extend({ + boundFalseyThing: false + }); + + Router.map(function() { + this.route('about', function() { + this.route('contact'); + }); + }); + + var hidden = 0; + + App.AboutRoute = Route.extend({ + actions: { + hide() { + hidden++; + } + } + }); + + bootApplication(); + + run(function() { + router.handleURL('/about'); + }); + + run(function() { + jQuery('#about-contact', '#qunit-fixture').click(); + }); + + equal(jQuery('#contact', '#qunit-fixture').text(), 'Contact', 'precond - the link worked'); + + equal(hidden, 0, 'The link didn\'t bubble'); +}); + QUnit.test('The {{link-to}} helper moves into the named route with context', function() { Router.map(function(match) { this.route('about'); @@ -686,6 +787,23 @@ QUnit.test('The {{link-to}} helper supports `target` attribute', function() { equal(link.attr('target'), '_blank', 'The self-link contains `target` attribute'); }); +QUnit.test('The {{link-to}} helper supports `target` attribute specified as a bound param', function() { + Ember.TEMPLATES.index = compile('

Home

{{#link-to \'index\' id=\'self-link\' target=boundLinkTarget}}Self{{/link-to}}'); + + App.IndexController = Controller.extend({ + boundLinkTarget: '_blank' + }); + + bootApplication(); + + run(function() { + router.handleURL('/'); + }); + + var link = jQuery('#self-link', '#qunit-fixture'); + equal(link.attr('target'), '_blank', 'The self-link contains `target` attribute'); +}); + QUnit.test('The {{link-to}} helper does not call preventDefault if `target` attribute is provided', function() { Ember.TEMPLATES.index = compile('

Home

{{#link-to \'index\' id=\'self-link\' target=\'_blank\'}}Self{{/link-to}}'); bootApplication(); @@ -1267,6 +1385,27 @@ QUnit.test('the {{link-to}} helper does not call preventDefault if `preventDefau equal(event.isDefaultPrevented(), false, 'should not preventDefault'); }); +QUnit.test('the {{link-to}} helper does not call preventDefault if `preventDefault=boundFalseyThing` is passed as an option', function() { + Ember.TEMPLATES.index = compile('{{#link-to \'about\' id=\'about-link\' preventDefault=boundFalseyThing}}About{{/link-to}}'); + + App.IndexController = Controller.extend({ + boundFalseyThing: false + }); + + Router.map(function() { + this.route('about'); + }); + + bootApplication(); + + run(router, 'handleURL', '/'); + + var event = jQuery.Event('click'); + jQuery('#about-link', '#qunit-fixture').trigger(event); + + equal(event.isDefaultPrevented(), false, 'should not preventDefault'); +}); + QUnit.test('the {{link-to}} helper does not throw an error if its route has exited', function() { expect(0); @@ -1523,3 +1662,52 @@ QUnit.test('Block-less {{link-to}} with only query-params updates when route cha }); equal(jQuery('#the-link').attr('href'), '/about?bar=NAW&foo=456', 'link has right href'); }); + +QUnit.test('The {{link-to}} helper can use dynamic params', function() { + Router.map(function(match) { + this.route('foo', { path: 'foo/:some/:thing' }); + this.route('bar', { path: 'bar/:some/:thing/:else' }); + }); + + let controller; + App.IndexController = Controller.extend({ + init() { + this._super(...arguments); + + controller = this; + + this.dynamicLinkParams = [ + 'foo', + 'one', + 'two' + ]; + } + }); + + Ember.TEMPLATES.index = compile(` +

Home

+ + {{#link-to params=dynamicLinkParams id="dynamic-link"}}Dynamic{{/link-to}} + `); + + bootApplication(); + + run(function() { + router.handleURL('/'); + }); + + let link = jQuery('#dynamic-link', '#qunit-fixture'); + + equal(link.attr('href'), '/foo/one/two'); + + run(function() { + controller.set('dynamicLinkParams', [ + 'bar', + 'one', + 'two', + 'three' + ]); + }); + + equal(link.attr('href'), '/bar/one/two/three'); +});