previously we were doing all kinds of checks to see if we should rewrite the url or not and we
were missing many scenarios. not any more.
with this change, we rewrite the url unless:
- the href is not set
- link has target attribute
- the absolute url of the link doesn't match the absolute prefix for all urls in our app
This also means that ng-ext-link attribute which we previously used to distinguish external
links from app links is not necessary any more. apps can just set target=_self to prevent
rewriting.
BREAKING CHANGE: ng-ext-link directive was removed because it's unnecessary
apps that relied on ng-ext-link should simply replace it with target=_self
previously it would create a new instance which wasn't configured as the one in the app,
which resulted in incorrect values being returned in html5 mode with base url set
Often it is impossible to set the http defaults during the config phase,
because the config info is not available at this time.
A good example is authentication - often the app needs to bootstrap,
allow user to enter credentials and only then it gains access to
session token which then should be sent to the server with every request.
Without having the ability to set the defaults at runtime, the developer
either has to resort to hacks, or has to set the session token header
with every request made by the app.
Create build for other modules as well (ngResource, ngCookies):
- wrap into a function
- add license
- add version
Breaks `$sanitize` service, `ngBindHtml` directive and `linky` filter were moved to the `ngSanitize` module. Apps that depend on any of these will need to load `angular-sanitize.js` and include `ngSanitize` in their dependency list: `var myApp = angular.module('myApp', ['ngSanitize']);`
this was never meant to be a public api used by apps. I refactored
the code to hide the functionality.
BREAKING CHANGE: $browser.addJs method was removed
apps that depended on this functionality should either use many of the
existing script loaders or create a simple helper method specific to the
app.
this api was never supposed to be public. nobody should be relying
on it.
I'm removing it since angular doesn't need it.
BREAKING CHANGE: $browser.addCss was removed
apps the depend on this functionality should write a simple utility
function specific to the app (see this diff for hints).
closure compiler is stubborn and puts the flag to the top of the file, so
we have to post-process the minified file to move the flag into the angular
closure.
Previously one had to write:
$routeProvider.when('/foo', {...});
$routeProvider.when('/bar', {...});
$routeProvider.otherwise({...});
After this change it's just:
$routeProvider.
when('/foo', {...}).
when('/bar', {...}).
otherwise({...});
Breaks #when which used to return the route definition object but now
returns self. Returning the route definition object is not very useful
so its likely that nobody ever used it.
The purpose of allowing the scope to be specified was to enable the $route service to work
together with ngInclude. However the functionality of creating scopes was in the recent past
moved from the $route service to the ngView directive, so currently there is no valid use case
for specifying the scope for ngInclude. In fact, allowing the scope to be defined can under
certain circumstances lead to memory leaks.
Breaks ngInclude does not have scope attribute anymore.
It turns out that listening only on "blur" event is not sufficient in many scenarios,
especially when you use form validation you always had to use ngModelnstant
e.g. if you want to disable a button based on valid/invalid form.
The feedback we got from our apps as well as external apps is that the
ngModelInstant should be the default.
In the future we might provide alternative ways of suppressing updates
on each key stroke, but it's not going to be the default behavior.
Apps already using the ngModelInstant can safely remove it from their
templates. Input fields without ngModelInstant directive will start propagating
the input changes into the model on each key stroke.
Previously if there was a white-space in fn: fn( ) {} we failed to infer no args.
This was originally reported by recht, but I decided to use a different fix.
Closes#829
We have many instances of this object and we clone them as well (e.g. ng-repeat).
This should save some memory and performance as well.
Double prefixed private properties of attr object:
attr.$element -> attr.$$element
attr.$observers -> attr.$$observers
Update shallowCopy to not copy $$ properties and allow passing optional destination object.
The `attr` object was only shallow copied which caused all observers to be shared.
Fixing similar issue in ng-* boolean attributes as well as ng-src and ng-href.
Instead of using our custom serializer we now use the native one and
use the replacer function to customize the serialization to preserve
most of the previous behavior (ignore $ and $$ properties as well
as window, document and scope instances).
$httpProvider.defaults.transformRequest and $httpProvider.defaults.transformResponse
are now arrays containing single function. This makes it easy to add an
extra transform fn.
adding an extra fn before had to be done in this cluncky way:
$httpProvider.defaults.transformResponse =
[$httpProvider.defaults.transformResponse, myTransformFn];
after this change, it's simply:
$httpProvider.defaults.transformResponse.push(myTransformFn);
Breaks angular.fromJson which doesn't deserialize date strings into date objects.
This was done to make fromJson compatible with JSON.parse.
If you do require the old behavior - if at all neeeded then because of
json deserialization of XHR responses - then please create a custom
$http transform:
$httpProvider.defaults.transformResponse.push(function(data) {
// recursively parse dates from data object here
// see code removed in this diff for hints
});
Closes#202
So that we can have non string values, e.g. ng-value="true" for radio inputs
Breaks boolean attrs are evaluated rather than interpolated
To migrate your code, change: <input ng-disabled="{{someBooleanVariable}}">
to: <input ng-disabled="someBooleanVariabla">
Affected directives:
* ng-multiple
* ng-selected
* ng-checked
* ng-disabled
* ng-readonly
* ng-required
This service has been accidentaly documented in the past, it should not be considered
to be public api.
I'm also removing fallback to Modernizr since we don't need it.
Breaks any app that depends on this service and its fallback to Modernizr, please
migrate to custom "Modernizr" service:
module.value('Modernizr', function() { return Modernizr; });
It's now possible to register controllers as:
.register('MyCtrl', function($scope) { ... });
// or
.register('MyCtrl', ['$scope', function($scope) { ... });
Additionally a module loader shortcut api was added as well:
myModule.controller('MyCtr', function($scope) { ... });
For typical app that has ng-app directive on the html element, we now can do:
angular.element(document).injector() or .injector()
angular.element(document).scope() or .scope()
instead of:
angular.element(document.getElementsByTagName('html')[0]).injector()
...
This makes for a much more flexible route matching:
- route /foo matches /foo and redirects /foo/ to /foo
- route /bar/ matches /bar/ and redirects /bar to /bar/
Closes#784
Compiler should not reassign values to element attributes if its not neccessary due
to interpolation or special attribute magic (ng-src -> src)
This resolves several issues on IE caused by reassigning script.src attribute which
caused all of the scripts to be reloaded.
In IE window.console.log and friends are functions that don't have apply or call fns.
For this reason we have to treat them specially and do our best to log at least
something when running in this browser.
Closes#805
In ie7 all of the input fields are set to readonly and disabled, because ie7 enumerates over all attributes even if the are not declared on the element.
Added support of timezone in dates not just zulu timezone.
This fixes issues for date filter which uses json deserialization under the hood. (for now)
Closes #/800
Fixed an issue where a directive that uses transclusion (such as ngRepeat) failed to link if it was declared on the root element of the compilation tree. (For example ngView or ngInclude including template where ngRepeat was the top most element).
corrected omitted assignment of controller to the element data object. Without this fix the controller created by ngView is not accessible from the browser debugger.
this is to enable nicer tests:
describe('fooSvc', function() {
var fooSvc;
beforeEach(inject(function(_fooSvc_) {
fooSvc = _fooSvc_;
}));
it('should do this thing', function() {
//test fooSvc
});
});
we can't provide this functionality because the directives are lazy
loaded when the module loads, which is too late for the shiv to do
anything useful.
- change custom onload directive to special arguments recongnized by both
ng-view and ng-include
- rename $contentLoaded event to $viewContentLoaded and $includeContentLoaded
- add event docs
It's more likely you are using angular.fromJson() inside Angular world, which means you get proper
exception handling by $exceptionHandler.
There is no point to explicitly push it to console and it causes memory leaks on most browsers
(tried Chrome stable/canary, Safari, FF).
Problems:
- controller was instantiated immediately on $afterRouteChange (even if no content), that's
different compare to ng:controller, which instantiates controllers after compiling
- route listened on current scope ($afterRouteChange), so if you were listening on $rootScope
($afterRouteChange), you get called first and current.scope === undefined, which is flaky
- route handles scope destroying, but scope is created by ng:view
- route fires after/before route change even if there is no route (when no otherwise specified)
Solution:
- route has no idea about scope, whole scope business moved to ng:view (creating/destroying)
- scope is created (and controller instantiated) AFTER compiling the content
- that means on $afterRouteChange - there is no scope yet (current.scope === undefined)
- added $contentLoaded event fired by ng:view, after linking the content
- remove $formFactory completely
- remove parallel scope hierarchy (forms, widgets)
- use new compiler features (widgets, forms are controllers)
- any directive can add formatter/parser (validators, convertors)
Breaks no custom input types
Breaks removed integer input type
Breaks remove list input type (ng-list directive instead)
Breaks inputs bind only blur event by default (added ng:bind-change directive)
Reason to fix this was the fact that with undefined url, it ended up with weird exception
(Cannot call method 'replace' of undefined), which was more confusing than helpful.
jQuery.ajax() does request to current url, if url is not specified, so I decided for this solution.
These methods cause IE8 holds the whole jqLite in the memory, even when page is reloaded.
jqLite's cache keeps element's data (event handlers, attached scopes, injector, etc…), so almost all used memory is never released in IE8.
jQuery creates its own Event object (wrapper around native Event) instead.
currently we run into infinite digest if a function is being
watched as an expression. This is because we generate bound
function wrapper when the watch is processed via parser.
I'm not too keen on the solution because it relies on the unbound
fn that is being exposed for other reasons, but I can't think
of a better way to deal with this right now
As scopes are injected into controllers now, you have the reference anyway, so having scope as first argument makes no sense…
Breaks $watcher gets arguments in different order (newValue, oldValue, scope)
Controller is standalone object, created using "new" operator, not messed up with scope anymore.
Instead, related scope is injected as $scope.
See design proposal: https://docs.google.com/document/pub?id=1SsgVj17ec6tnZEX3ugsvg0rVVR11wTso5Md-RdEmC0kCloses#321Closes#425
Breaks controller methods are not exported to scope automatically
Breaks Scope#$new() does not take controller as argument anymore
Chrome (probably other browsers as well) fires 'hashchange' event synchronously, so if you change raw location from within $apply/$digest, we don't want to $apply twice. (It would throw an exception)
- there are too many unknowns about PATCH, so I'm dropping its support until we know that this is actually useful
- expectGET, expectHEAD and expectJSON (and the same for whenXXX) should not require response data to be specified
Now, that we have autoscroll attribute on ng:include, there is no reason to disable the service completely, so $anchorScrollProvider.disableAutoScrolling() means it won't be scrolling when $location.hash() changes.
And then, it's not $autoScroll at all, it actually scrolls to anchor when it's called, so I renamed
it to $anchorScroll.
$http:
- use promises internally
- get rid of XhrFuture that was previously used internally
- get rid of $browser.defer calls for async stuff (serving from cache),
promises will take care of asynchronicity
- fix transformation bugs (when caching requested + multiple request
pending + error is returned)
- get rid of native header parsing and instead just lazily parse the
header string
$httpBackend:
- don't return raw/mock XMLHttpRequest object (we don't use it for
anything anymore)
- call the callback with response headers string
mock $httpBackend:
- unify response api for expect and when
- call the callback with response headers string
- changed the expect/when failure error message so that EXPECTED and GOT
values are aligned
Conflicts:
src/service/http.js
test/service/compilerSpec.js
test/service/httpSpec.js
The input event is fired on all non-ie browsers whenever the contents of an input
field changes. This means that we now support cut&paste via mouse which
was previously unsupported.
IE8 and older don't support this events and IE9 has a problematic
support for it, so we can't rely solely on this event and drop keydown
and change events.
Previously we used to put callbacks on the window object, but that
causes problems on IE8 where it is not possible to delete properties
from the window object
closure compiler is smarter than we expected and drops the unused fn
argument - this breaks the meta-programing logic of jqLite.
The fix special cases JQLiteHasClass since its the only fn that needs
this treatment in a way that is minification-proof.
This fix is similar to what I've done in ng:view, if a new template has been requested before the
callback for the previous template returned, ignore it. Otherwise weird race conditions happen
and users might end up getting the content for the previous include rendered instead of the most
recent one.
Parser now builds expressions that can detect promises and transparently
evaluate them to undefined or the promise value.
If promiseA is resolved with value 'A', then {{promiseA}} evals to 'A';
If promiseA is unresolved, then {{promiseA}} evals to undefined;
Following invocations are supported:
- {{promise}}
- {{promise.futureProp}}
- {{[promise][0]}}
- {{object.promise}}
- {{object[promise]}}
- {{array[promise]}}
- {{fn(promise)}}
- combinations of the above
If jsonp is not successfull, we return internal status -2.
This internal status should by normalized by $xhr into 0,
but $xhr needs to distinguish between jsonp-error/abort/timeout (all status 0).
- since NaN !== NaN in javascript digest can get into an infinite loop
when model value is set to NaN
- angular.equals(NaN, NaN) should return true since that's what we
expect when comparing primitives or objects containing NaN values
Previously NaN because of its special === properties was used as the
initial value for watches, but that results in issues when NaN is used
as model value.
In order to allow for model to be anything incuding undefined and NaN we
need to mark the initial value differently in a way that would avoid
these issues, allow us to run digest without major perf penalties and
allow for clients to determine if the listener is being called because
the watcher is being initialized or because the model changed. This
implementation covers all of these scenarios.
BREAKING CHANGE: previously to detect if the listener was called because
the watcher was being initialized, it was suggested that clients check
if old value is NaN. With this change, the check should be if the newVal
equals the oldVal.
Closes#657
- turn scope into a $rootScope service.
- injector is now a starting point for creating angular application.
- added inject() method which wraps jasmine its/beforeEach/afterEach,
and which allows configuration and injection of services.
- refactor tests to use inject() where possible
BREAK:
- removed angular.scope() method
- better compatibility with 3rd party code - we clober 3rd party
style only if it direcrtly collides with 3rd party styles
- better perf since it doesn't execute stuff on every digest
- lots of tests
Commit 5a2dcb9a doesn't properly modify angular-boostrap.js.
This fix resolves issues and makes both the regular and scenario
version of angular-boostrap.js functional.
The last script element in the dom is always us if the script that
contains angular is loaded synchronously.
For async loading manual bootstrap needs to be performed.
Close#621
Along the way I also changed the repeater impl to use for loop instead
of for in loop.
Iteration over objects is handled by creating an array of keys, which is
sorted and this array then determines the order of iteration over an
element. This makes repeating over objects deterministic and
cross-browser compatible.
A lot of badness happens when we don't ignore stale xhrs. These
raceconditions are only apparent when user clicks through the app very
quckly without waiting for routes to fully load.
Closes#619
This functionality was previously available only as obscure $browser.defer.cancel.
I also added docs and tests and fixed an issue in .defer.cancel mock.
For example:
<a href="some/link">inner <span>text</span></a>
If you click on "text", then the span element is event.target, so we need to traverse the DOM.
Change introduced by me in 8611ebe6 results in considerable inefficiencies when the compiler
and linker is used from within a widget, in which case, we call $digest unnecessary since it
will be called by the $apply which called the directive/widget in the first place.
There are only two places when the extra $digest call can be useful - when manually bootstrapping
the app or in tests. However even in tests this behavior can result in unwanted results (especially
when ng:controller is involved). So it is better to leave it for the developer to call $digest
when it is really needed.
Because only controllers don't have currying, we can infer its arguments, all other APIs needing currying, automatic inference complicates the matters unecessary.