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

feat(ionContent): use child scope instead of isolate scope #669

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
61 changes: 38 additions & 23 deletions js/ext/angular/src/directive/ionicContent.js
Expand Up @@ -18,33 +18,23 @@ angular.module('ionic.ui.content', ['ionic.ui.service', 'ionic.ui.scroll'])

// The content directive is a core scrollable content area
// that is part of many View hierarchies
.directive('ionContent', ['$parse', '$timeout', '$ionicScrollDelegate', '$controller', function($parse, $timeout, $ionicScrollDelegate, $controller) {
.directive('ionContent', [
'$parse',
'$timeout',
'$ionicScrollDelegate',
'$controller',
'$ionicBind',
function($parse, $timeout, $ionicScrollDelegate, $controller, $ionicBind) {
return {
restrict: 'E',
replace: true,
template: '<div class="scroll-content"><div class="scroll" ng-transclude></div></div>',
transclude: true,
require: '^?ionNavView',
scope: {
onRefresh: '&',
onRefreshOpening: '&',
onScroll: '&',
onScrollComplete: '&',
refreshComplete: '=',
onInfiniteScroll: '=',
infiniteScrollDistance: '@',
hasBouncing: '@',
scroll: '@',
padding: '@',
hasScrollX: '@',
hasScrollY: '@',
scrollbarX: '@',
scrollbarY: '@',
startX: '@',
startY: '@',
scrollEventInterval: '@'
},

scope: true,
template:
'<div class="scroll-content">' +
'<div class="scroll"></div>' +
'</div>',
compile: function(element, attr, transclude) {
if(attr.hasHeader == "true") { element.addClass('has-header'); }
if(attr.hasSubheader == "true") { element.addClass('has-subheader'); }
Expand All @@ -60,7 +50,31 @@ angular.module('ionic.ui.content', ['ionic.ui.service', 'ionic.ui.scroll'])

function prelink($scope, $element, $attr, navViewCtrl) {
var clone, sc, scrollView, scrollCtrl,
c = angular.element($element.children()[0]);
scrollContent = angular.element($element[0].querySelector('.scroll'));

transclude($scope, function(clone) {
scrollContent.append(clone);
});

$ionicBind($scope, $attr, {
onRefresh: '&',
onRefreshOpening: '&',
onScroll: '&',
onScrollComplete: '&',
refreshComplete: '=',
onInfiniteScroll: '&',
infiniteScrollDistance: '@',
hasBouncing: '@',
scroll: '@',
padding: '@',
hasScrollX: '@',
hasScrollY: '@',
scrollbarX: '@',
scrollbarY: '@',
startX: '@',
startY: '@',
scrollEventInterval: '@'
});

if($scope.scroll === "false") {
// No scrolling
Expand Down Expand Up @@ -92,6 +106,7 @@ angular.module('ionic.ui.content', ['ionic.ui.service', 'ionic.ui.scroll'])
}
}
});

//Publish scrollView to parent so children can access it
scrollView = $scope.$parent.scrollView = scrollCtrl.scrollView;

Expand Down
1 change: 1 addition & 0 deletions js/ext/angular/src/ionicAngular.js
Expand Up @@ -3,6 +3,7 @@
* modules.
*/
angular.module('ionic.service', [
'ionic.service.bind',
'ionic.service.platform',
'ionic.service.actionSheet',
'ionic.service.gesture',
Expand Down
52 changes: 52 additions & 0 deletions js/ext/angular/src/service/ionicBind.js
@@ -0,0 +1,52 @@
angular.module('ionic.service.bind', [])
.factory('$ionicBind', ['$parse', '$interpolate', function($parse, $interpolate) {
var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
return function(scope, attrs, bindDefinition) {
angular.forEach(bindDefinition || {}, function (definition, scopeName) {
//Adapted from angular.js $compile
var match = definition.match(LOCAL_REGEXP) || [],
attrName = match[3] || scopeName,
mode = match[1], // @, =, or &
parentGet,
unwatch;

switch(mode) {
case '@':
if (!attrs[attrName]) {
return;
}
attrs.$observe(attrName, function(value) {
scope[scopeName] = value;
});
// we trigger an interpolation to ensure
// the value is there for use immediately
if (attrs[attrName]) {
scope[scopeName] = $interpolate(attrs[attrName])(scope);
}
break;

case '=':
if (!attrs[attrName]) {
return;
}
unwatch = scope.$watch(attrs[attrName], function(value) {
scope[scopeName] = value;
});
//Destroy parent scope watcher when this scope is destroyed
scope.$on('$destroy', unwatch);
break;

case '&':
if (attrs[attrName] && attrs[attrName].match(RegExp(scopeName + '\(.*?\)'))) {
throw new Error('& expression binding "' + scopeName + '" looks like it will recursively call "' +
attrs[attrName] + '" and cause a stack overflow! Please choose a different scopeName.');
}
parentGet = $parse(attrs[attrName]);
scope[scopeName] = function(locals) {
return parentGet(scope, locals);
};
break;
}
});
};
}]);
37 changes: 27 additions & 10 deletions js/ext/angular/test/directive/ionicContent.unit.js
@@ -1,5 +1,5 @@
describe('Ionic Content directive', function() {
var compile, element, scope;
var compile, scope;

beforeEach(module('ionic'));

Expand All @@ -12,22 +12,22 @@ describe('Ionic Content directive', function() {
}));

it('Has $ionicScroll controller', function() {
element = compile('<ion-content></ion-content>')(scope);
var element = compile('<ion-content></ion-content>')(scope);
expect(element.controller('$ionicScroll').element).toBe(element[0]);
});

it('Has content class', function() {
element = compile('<ion-content></ion-content>')(scope);
var element = compile('<ion-content></ion-content>')(scope);
expect(element.hasClass('scroll-content')).toBe(true);
});

it('Has header', function() {
element = compile('<ion-content has-header="true"></ion-content>')(scope);
var element = compile('<ion-content has-header="true"></ion-content>')(scope);
expect(element.hasClass('has-header')).toEqual(true);
});

it('should add padding classname', function() {
element = compile('<ion-content padding="true"></ion-content>')(scope);
var element = compile('<ion-content padding="true"></ion-content>')(scope);
expect(element.hasClass('scroll-content')).toEqual(true);
expect(element.hasClass('padding')).toEqual(false);
var scrollElement = element.find('.scroll');
Expand All @@ -36,7 +36,7 @@ describe('Ionic Content directive', function() {

// it('Enables bouncing by default', function() {
// ionic.Platform.setPlatform('iPhone');
// element = compile('<ion-content has-header="true"></ion-content>')(scope);
// var element = compile('<ion-content has-header="true"></ion-content>')(scope);
// scope.$apply();
// var newScope = element.isolateScope();
// var scrollView = scope.scrollView;
Expand All @@ -45,7 +45,7 @@ describe('Ionic Content directive', function() {

it('Disables bouncing when has-bouncing = false', function() {
ionic.Platform.setPlatform('iPhone');
element = compile('<ion-content has-header="true" has-bouncing="false"></ion-content>')(scope);
var element = compile('<ion-content has-header="true" has-bouncing="false"></ion-content>')(scope);
scope.$apply();
var newScope = element.isolateScope();
var scrollView = scope.scrollView;
Expand All @@ -54,7 +54,7 @@ describe('Ionic Content directive', function() {

it('Disables bouncing by default on Android', function() {
ionic.Platform.setPlatform('Android');
element = compile('<ion-content has-header="true"></ion-content>')(scope);
var element = compile('<ion-content has-header="true"></ion-content>')(scope);
scope.$apply();
var newScope = element.isolateScope();
var scrollView = scope.scrollView;
Expand All @@ -63,7 +63,7 @@ describe('Ionic Content directive', function() {

it('Disables bouncing by default on Android unless has-bouncing = true', function() {
ionic.Platform.setPlatform('Android');
element = compile('<ion-content has-header="true" has-bouncing="true"></ion-content>')(scope);
var element = compile('<ion-content has-header="true" has-bouncing="true"></ion-content>')(scope);
scope.$apply();
var newScope = element.isolateScope();
var scrollView = scope.scrollView;
Expand All @@ -72,7 +72,7 @@ describe('Ionic Content directive', function() {


it('Should set start x and y', function() {
element = compile('<ion-content start-x="100" start-y="300" has-header="true"></ion-content>')(scope);
var element = compile('<ion-content start-x="100" start-y="300" has-header="true"></ion-content>')(scope);
scope.$apply();
var newScope = element.isolateScope();
var scrollView = scope.scrollView;
Expand Down Expand Up @@ -139,3 +139,20 @@ describe('Ionic Content directive', function() {
});
});
});
/* Tests #555 */
describe('Ionic Content Directive scoping', function() {
beforeEach(module('ionic', function($controllerProvider) {
$controllerProvider.register('ContentTestCtrl', function($scope){
this.$scope = $scope;
});
}));
it('should have same scope as content', inject(function($compile, $rootScope) {
var element = $compile('<ion-content ng-controller="ContentTestCtrl">' +
'<form name="myForm"></form>' +
'</ion-content>')($rootScope.$new());
var contentScope = element.scope();
var ctrl = element.data('$ngControllerController');
expect(contentScope.myForm).toBeTruthy();
expect(ctrl.$scope.myForm).toBeTruthy();
}));
});
12 changes: 11 additions & 1 deletion js/ext/angular/test/list-fit.html
Expand Up @@ -14,7 +14,7 @@

<ion-header-bar title="'Sample UL'" type="bar-positive"></ion-header-bar>

<ion-content has-header="true" scroll="true" ng-controller="ContentCtrl" on-refresh="onRefresh()" has-footer="true" padding="false">
<ion-content on-infinite-scroll="addMore()" has-header="true" scroll="true" ng-controller="ContentCtrl" on-refresh="onRefresh()" has-footer="true" padding="false">

<ion-refresher></ion-refresher>

Expand Down Expand Up @@ -45,7 +45,11 @@
<li class="item">24</li>
<li class="item">25</li>
<li class="item">26</li>
<li ng-repeat="i in more">more {{$index}}</li>
</ul>

<ion-infinite-scroll></ion-infinite-scroll>

</ion-content>

<ion-footer-bar type="bar-assertive">
Expand All @@ -59,6 +63,12 @@ <h1 class="title">Footer!</h1>
$scope.$broadcast('scroll.refreshComplete');
}, 1000);
};
$scope.more = [];
$scope.addMore = function() {
for (var i=0; i<15; i++) {
$scope.more.push(i);
}
};
}
</script>

Expand Down
Expand Up @@ -34,7 +34,7 @@ describe('Ionic ScrollDelegate Service', function() {
it('scroll event', function() {
var scope = rootScope.$new();
var el = compile('<ion-content></ion-content>')(scope);
scope = el.isolateScope();
scope = el.scope();
scope.$apply();
var top, left;
scope.onScroll = jasmine.createSpy('scroll').andCallFake(function(data) {
Expand Down