Skip to content

Commit 4559c32

Browse files
fix(routeToComponent): Bind resolves that start with data- or x-
Allow routing to components and binding resolves with names like `xComponent` or `dataComponent` or `xResolve` or `dataResolve` - Prefix all resolve attributes in generated template with `x-`: `<x-mycmp x-data-value="::$resolve.dataValue"></x-mycmp>` - Prefix all component names in generated template with `x-`: `<x-mycmp></x-mycmp>` Closes #3276
1 parent 8e7386b commit 4559c32

File tree

4 files changed

+195
-119
lines changed

4 files changed

+195
-119
lines changed

src/directives/viewDirective.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -387,9 +387,12 @@ function $ViewDirectiveFill ($compile: ICompileService, $controller: IController
387387
if (isString(cfg.viewDecl.component)) {
388388
let cmp = cfg.viewDecl.component;
389389
let kebobName = kebobString(cmp);
390+
let tagRegexp = new RegExp(`^(x-|data-)?${kebobName}$`, "i");
391+
390392
let getComponentController = () => {
391393
let directiveEl = [].slice.call($element[0].children)
392-
.filter((el: Element) => el && el.tagName && el.tagName.toLowerCase() === kebobName) ;
394+
.filter((el: Element) => el && el.tagName && tagRegexp.exec(el.tagName)) ;
395+
393396
return directiveEl && angular.element(directiveEl).data(`$${cmp}Controller`);
394397
};
395398

src/templateFactory.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ export class TemplateFactory implements TemplateFactoryProvider {
148148
// then pass that attribute through to the routed component template.
149149
// Prefer ui-view wired mappings to resolve data, unless the resolve was explicitly bound using `bindings:`
150150
if (uiView.attr(attrName) && !bindings[name])
151-
return `${attrName}='${uiView.attr(attrName)}'`;
151+
return `x-${attrName}='${uiView.attr(attrName)}'`;
152152

153153
let resolveName = bindings[name] || name;
154154
// Pre-evaluate the expression for "@" bindings by enclosing in {{ }}
155155
// some-attr="{{ ::$resolve.someResolveName }}"
156156
if (type === '@')
157-
return `${attrName}='{{${prefix}$resolve.${resolveName}}}'`;
157+
return `x-${attrName}='{{${prefix}$resolve.${resolveName}}}'`;
158158

159159
// Wire "&" callbacks to resolves that return a callback function
160160
// Get the result of the resolve (should be a function) and annotate it to get its arguments.
@@ -165,15 +165,15 @@ export class TemplateFactory implements TemplateFactoryProvider {
165165
let args = fn && services.$injector.annotate(fn) || [];
166166
// account for array style injection, i.e., ['foo', function(foo) {}]
167167
let arrayIdxStr = isArray(fn) ? `[${fn.length - 1}]` : '';
168-
return `${attrName}='$resolve.${resolveName}${arrayIdxStr}(${args.join(",")})'`;
168+
return `x-${attrName}='$resolve.${resolveName}${arrayIdxStr}(${args.join(",")})'`;
169169
}
170170

171171
// some-attr="::$resolve.someResolveName"
172-
return `${attrName}='${prefix}$resolve.${resolveName}'`;
172+
return `x-${attrName}='${prefix}$resolve.${resolveName}'`;
173173
};
174174

175175
let attrs = getComponentBindings(component).map(attributeTpl).join(" ");
176-
let kebobName = kebobString(component);
176+
let kebobName = "x-" + kebobString(component);
177177
return `<${kebobName} ${attrs}></${kebobName}>`;
178178
};
179179
}

test/viewDirectiveSpec.ts

+34
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,15 @@ describe('angular 1.5+ style .component()', function() {
902902
template: 'eventCmp',
903903
});
904904

905+
app.component('mydataComponent', {
906+
bindings: { dataUser: '<' },
907+
template: '-{{ $ctrl.dataUser }}-',
908+
});
909+
910+
app.component('dataComponent', {
911+
template: 'DataComponent',
912+
});
913+
905914
app.component('parentCallbackComponent', {
906915
controller: function($rootScope) {
907916
this.handleEvent = function(foo, bar) {
@@ -1164,6 +1173,31 @@ describe('angular 1.5+ style .component()', function() {
11641173
expect(el.text()).toBe('eventCmp');
11651174
});
11661175

1176+
// Test for #3276
1177+
it('should route to a component that is prefixed with "data"', function () {
1178+
$stateProvider.state('data', {
1179+
component: 'dataComponent',
1180+
});
1181+
1182+
let $state = svcs.$state, $q = svcs.$q;
1183+
$state.transitionTo('data'); $q.flush();
1184+
1185+
expect(el.text()).toBe('DataComponent');
1186+
});
1187+
1188+
// Test for #3276
1189+
it('should bind a resolve that is prefixed with "data"', function () {
1190+
$stateProvider.state('data', {
1191+
component: 'mydataComponent',
1192+
resolve: { dataUser: () => 'user' }
1193+
});
1194+
1195+
let $state = svcs.$state, $q = svcs.$q;
1196+
$state.transitionTo('data'); $q.flush();
1197+
1198+
expect(el.text()).toBe('-user-');
1199+
});
1200+
11671201
// Test for #3239
11681202
it('should pass any bindings (wired from a parent component template via the ui-view) through to the child', inject(function ($rootScope) {
11691203
let $state = svcs.$state, $q = svcs.$q;

0 commit comments

Comments
 (0)