Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

feat(jqLite): implement jqLite(f) as alias to jqLite(document).ready(f) (also: deprecate the latter in the second commit) #15237

Closed
wants to merge 5 commits 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/content/guide/bootstrap.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Here is an example of manually initializing Angular:
$scope.greetMe = 'World';
}]);

angular.element(document).ready(function() {
angular.element(function() {
angular.bootstrap(document, ['myApp']);
});
</script>
Expand Down Expand Up @@ -167,4 +167,4 @@ until `angular.resumeBootstrap()` is called.

`angular.resumeBootstrap()` takes an optional array of modules that
should be added to the original list of modules that the app was
about to be bootstrapped with.
about to be bootstrapped with.
7 changes: 3 additions & 4 deletions src/angular.bind.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
if (window.angular.bootstrap) {
//AngularJS is already loaded, so we can return here...
// AngularJS is already loaded, so we can return here...
if (window.console) {
console.log('WARNING: Tried to load angular more than once.');
}
return;
}

//try to bind to jquery now so that one can write jqLite(document).ready()
//but we will rebind on bootstrap again.
// try to bind to jquery now so that one can write jqLite(fn)
// but we will rebind on bootstrap again.
bindJQuery();

2 changes: 1 addition & 1 deletion src/angular.suffix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
jqLite(window.document).ready(function() {
jqLite(function() {
angularInit(window.document, bootstrap);
});

Expand Down
49 changes: 27 additions & 22 deletions src/jqLite.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
* - [`after()`](http://api.jquery.com/after/)
* - [`append()`](http://api.jquery.com/append/)
* - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
* - [`bind()`](http://api.jquery.com/bind/) (_deprecated_ - to be removed in 1.7.0, use [`on()`](http://api.jquery.com/on/)) - Does not support namespaces, selectors or eventData
* - [`bind()`](http://api.jquery.com/bind/) (_deprecated_, use [`on()`](http://api.jquery.com/on/)) - Does not support namespaces, selectors or eventData
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
* - [`clone()`](http://api.jquery.com/clone/)
* - [`contents()`](http://api.jquery.com/contents/)
Expand All @@ -76,7 +76,7 @@
* - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
* - [`prepend()`](http://api.jquery.com/prepend/)
* - [`prop()`](http://api.jquery.com/prop/)
* - [`ready()`](http://api.jquery.com/ready/)
* - [`ready()`](http://api.jquery.com/ready/) (_deprecated_, use `angular.element(callback)` instead of `angular.element(document).ready(callback)`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

document removal in 1.7?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be discussed; see #15221.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conclusion: no removal note.

* - [`remove()`](http://api.jquery.com/remove/)
* - [`removeAttr()`](http://api.jquery.com/removeAttr/) - Does not support multiple attributes
* - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
Expand All @@ -85,7 +85,7 @@
* - [`text()`](http://api.jquery.com/text/)
* - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument
* - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers
* - [`unbind()`](http://api.jquery.com/unbind/) (_deprecated_ - to be removed in 1.7.0, use [`off()`](http://api.jquery.com/off/)) - Does not support namespaces or event object as parameter
* - [`unbind()`](http://api.jquery.com/unbind/) (_deprecated_, use [`off()`](http://api.jquery.com/off/)) - Does not support namespaces or event object as parameter
* - [`val()`](http://api.jquery.com/val/)
* - [`wrap()`](http://api.jquery.com/wrap/)
*
Expand Down Expand Up @@ -288,6 +288,8 @@ function JQLite(element) {

if (argIsString) {
jqLiteAddNodes(this, jqLiteParseHTML(element));
} else if (isFunction(element)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't this go above the instanceof JQLite check?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to delay the most common path and jQuery has this check below the selector code. Maybe with JITs it's not a problem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably not a problem, but it can't do much damage either (how many times would one call jqLite(fn)?).
So if jQuery has it this way, let's leave it as is.

Copy link
Member Author

@mgol mgol Oct 10, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jQuery is slightly different as it handles nodes after the function.

Maybe we should apply this here as well? That would only require an additional check for nodeType.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, jQuery does it as it's done here, I read the code incorrectly.

jqLiteReady(element);
} else {
jqLiteAddNodes(this, element);
}
Expand Down Expand Up @@ -519,29 +521,32 @@ function jqLiteDocumentLoaded(action, win) {
}
}

function jqLiteReady(fn) {
function trigger() {
window.document.removeEventListener('DOMContentLoaded', trigger);
window.removeEventListener('load', trigger);
fn();
}

// check if document is already loaded
if (window.document.readyState === 'complete') {
window.setTimeout(fn);
} else {
// We can not use jqLite since we are not done loading and jQuery could be loaded later.

// Works for modern browsers and IE9
window.document.addEventListener('DOMContentLoaded', trigger);

// Fallback to window.onload for others
window.addEventListener('load', trigger);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By using addEventListener (here and above) doesn't it mean the people can't use .triggerHandler()?
It could break apps (and even more likely tests).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does but we no longer have an underlying element and that's what jQuery uses so this is aligning with jQuery.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Should we document it as breaking change then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it shouldn't be possible to exercise the difference from a test, since you can't stop the DOMContentLoaded/load events. So, it's fine, I guess.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let's document it. I need to think about the phrasing that will make it clear it's an edge case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...or do you mean it's not a breaking change in your last commit?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'll assume there's nothing to do here. :D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I meant let's not consider it a breaking change 😃

}
}

//////////////////////////////////////////
// Functions which are declared directly.
//////////////////////////////////////////
var JQLitePrototype = JQLite.prototype = {
ready: function(fn) {
var fired = false;

function trigger() {
if (fired) return;
fired = true;
fn();
}

// check if document is already loaded
if (window.document.readyState === 'complete') {
window.setTimeout(trigger);
} else {
this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
// we can not use jqLite since we are not done loading and jQuery could be loaded later.
// eslint-disable-next-line new-cap
JQLite(window).on('load', trigger); // fallback to window.onload for others
}
},
ready: jqLiteReady,
toString: function() {
var value = [];
forEach(this, function(e) { value.push('' + e);});
Expand Down
2 changes: 1 addition & 1 deletion src/ngScenario/angular.suffix
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ angular.forEach(script.attributes, function(attr) {
});

if (config.autotest) {
JQLite(window.document).ready(function() {
JQLite(function() {
angular.scenario.setUpAndRun(config);
});
}
Expand Down
13 changes: 13 additions & 0 deletions test/e2e/fixtures/ready/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html ng-app="test" ng-jq>
<body>
<span class="before-ready">{{beforeReady}}</span>
<span class="after-ready">{{afterReady}}</span>
<span class="after-ready-sync">{{afterReadySync}}</span>
<span class="after-ready-method">{{afterReadyMethod}}</span>
<span class="after-ready-method-sync">{{afterReadyMethodSync}}</span>
<script src="angular.js"></script>
<script src="script.js"></script>
<div id="div-after-scripts">This div is loaded after scripts.</div>
</body>
</html>
32 changes: 32 additions & 0 deletions test/e2e/fixtures/ready/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';

var beforeReady;
(function() {
var divAfterScripts = window.document.getElementById('div-after-scripts');
beforeReady = divAfterScripts && divAfterScripts.textContent;
})();

var afterReady;
angular.element(function() {
var divAfterScripts = window.document.getElementById('div-after-scripts');
afterReady = divAfterScripts && divAfterScripts.textContent;
});

var afterReadyMethod;
angular.element(window.document).ready(function() {
var divAfterScripts = window.document.getElementById('div-after-scripts');
afterReadyMethod = divAfterScripts && divAfterScripts.textContent;
});

var afterReadySync = afterReady;
var afterReadyMethodSync = afterReadyMethod;

angular
.module('test', [])
.run(function($rootScope) {
$rootScope.beforeReady = beforeReady;
$rootScope.afterReady = afterReady;
$rootScope.afterReadySync = afterReadySync;
$rootScope.afterReadyMethod = afterReadyMethod;
$rootScope.afterReadyMethodSync = afterReadyMethodSync;
});
25 changes: 25 additions & 0 deletions test/e2e/tests/ready.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

describe('Firing a callback on ready', function() {
it('should not have the div available immediately', function() {
loadFixture('ready');
expect(element(by.className('before-ready')).getText())
.toBe('');
});

it('should wait for document ready', function() {
loadFixture('ready');
expect(element(by.className('after-ready')).getText())
.toBe('This div is loaded after scripts.');
expect(element(by.className('after-ready-method')).getText())
.toBe('This div is loaded after scripts.');
});

it('should be asynchronous', function() {
loadFixture('ready');
expect(element(by.className('after-ready-sync')).getText())
.toBe('');
expect(element(by.className('after-ready-method-sync')).getText())
.toBe('');
});
});