I'm using angular-ui-tinymce (latest version 0.0.4, https://github.com/angular-ui/ui-tinymce/blob/master/src/tinymce.js).
I've encountered a problem I cannot solve.
On the first page load, content is loaded to the editor via ng-model.
Then I navigate to another state and then navigating back to state with the editor.
The value still exists on the scope (I've checked it) but the content doesn't appear in the editor for some reason I cant figure..
This is the the textarea with the directive as attribute:
<textarea rows="10" class="form-control" id="desc" ui-tinymce ng-model="valueFromScope"></textarea>
This changes happened after updating AngularJS from 1.5 to 1.2.1.
I thought it had something to do with ngSanitize but I'm not sure..
btw angular-sanitize and ngSanitize are included in the app.
Any advice?
update
It seems like ngModel.$render is not doing anything.
ngModel.$render = function() {
console.log(ngModel);
tinyInstance = tinymce.get(attrs.id);
if (tinyInstance) {
tinyInstance.setContent(ngModel.$viewValue || '');
updateView();
}
};
Nothing is printed out, not even undefined, this means ngModel.$render doesn't even run.
Any reasons for that?
Update
I don't think model.$render is related, from what I understand $render only executes on a programmatic change like actually editing the text and that works..
I still can't figure it out, sometimes the value is shown and sometimes not.
Problem Solved! - for now..
Thanks to #alonisser I've found a solution.
From what I understand, the problem is occurring because something has changed in the prioritizing of angularjs directives.
read the following:
http://iwang.github.io/html/angular/angularjs/2013/11/04/ngmodel-render-cannot-be-overriden-in-angular-rc3.html
the simple fix is just to add priority definition to the directive
return {
priority: 10,
require: 'ngModel',
Setting the priority doesn't really solve the problem.
The only thing that worked for me was adding the following code before the ngModel.$render = function()
var stopWatch = scope.$watch(attrs.ngModel, function(newValue){
if (!tinyInstance){
tinyInstance = tinymce.get(attrs.id);
}
if (tinyInstance) {
tinyInstance.setContent(newValue);
stopWatch();
}
});
Related
I'm encountering a very weird issue where class directives just will not work. So I'm trying to implement the following directive.
appModule.directive('btn', function () {
return {
restrict: 'C',
link: function (scope, element) {
if (element.hasClass('btn-icon') || element.hasClass('btn-float')) {
Waves.attach(element, ['waves-circle']);
}
else if (element.hasClass('btn-light')) {
Waves.attach(element, ['waves-light']);
}
else {
Waves.attach(element);
}
Waves.init();
}
}
});
Then In my HTML I just have a button with the class btn, like so.
<button type="button" class='btn btn-success'>Hello</button>
But for some reason it just won't EVER fire the directive. I've tried debugging using console.log, it's just not entering the directive itself. But when I change restrict: 'C' from C to E, it works fine! (with altered HTML ofcourse.)
Now we do use a small framework on top of angularJS, but haven't found anything weird in there. (I recently joined the team, and the orignal developer of the framework didn't write any documentation and has left the team).
What could possibly be a reason why this directive would not work? I've googled everywhere but I can't find anyone with a similar issue.
So after looking at the code for hours, I finally found what it was. So someone that wrote the official code added in this line of code....
$compileProvider.cssClassDirectivesEnabled(false);
Changed this to true, and it works..
Here is the link to the code:
http://plnkr.co/edit/usrmiNkj5YJY5SlV8ETw?p=preview
Open up your javascript console and click on "say hi". It will trigger an error that $apply is already in progress.
But when you remove this piece of code:
ng-controller="mouseEvents" ng-mousedown="onMouseDown()" ng-mouseup="onMouseUp()" ng-mousemove="onMouseMove()"
and after saving when you click on "say hi" the error is gone.
How can I solve this?
I need the mouseEvents to set flags if the mouse is down or if it is up for multiple different controllers. I can not simply remove it in my code.
Edit:
Newer angular version solved my issue without $timeout v1.3.10 or higher
Use $timeout to let angular finish dirty checking then show the alert.
app.controller("demoController",function($scope,$window, $timeout){
$scope.save = function(){
$timeout(function(){
window.alert("hi!");
});
};
});
Plunkr: http://plnkr.co/edit/Kxbey5Rc43xsB9v5ugZ5?p=preview
The typeahead display gets stuck to the body when using append to body in combination with routing.
typeahead-append-to-body="true"
I used the Angular seed project and one of the simple Typeahead examples and replicated the problem: http://plnkr.co/WSNIRKLqOCLqO87jp3an
Load page
Select 'view2'
Select 'view1'
Type alpha character 'a' into the input
Observe the typeahead display attached to the body
Select view2
Observe display is still attached to the body
Problem happens in all the browsers I tried.
I see the click bindings to the document fire but the dismissClickHandler is not called if the page is has been routed to before. Meaning it works fine the first time, but when you go back to a page that you have been to before it never firs the dismissClickHandler.
https://github.com/angular-ui/bootstrap/blob/master/src/typeahead/typeahead.js
// Keep reference to click handler to unbind it.
var dismissClickHandler = function (evt) {
if (element[0] !== evt.target) {
resetMatches();
scope.$digest();
}
};
$document.bind('click', dismissClickHandler);
originalScope.$on('$destroy', function(){
$document.unbind('click', dismissClickHandler);
});
var $popup = $compile(popUpEl)(scope);
if ( appendToBody ) {
$document.find('body').append($popup);
} else {
element.after($popup);
}
Any thoughts?
Please note that this is fixed using the latest versions of Angular (1.4.7) and Angular UI Bootstrap (0.14.3) - at the time of this writing. As such, I've closed https://github.com/angular-ui/bootstrap/issues/2551.
I believe this is a bug of the angular-bootstrap to not call $popup.remove() when its scope has been destroyed.
The reason it seems to work fine at the first time is because when you navigate to view 2, the template has't been ready in a cache yet, so it take sometime to load, and that allow the dismissClickHandler() to get executed and hide a popup.
But just hidding the popup is not enough. It should be removed from the DOM.
In your plunker, if you navigate back and forth between views a few times, then inspect the DOM, you will see a lot of dangling ui elements are still there but hidden in the document.body.
runTarm put me on the right track. This is my (quite dirty) fix, I remove the typeahead from the DOM on destroy of the scope:
originalScope.$on('$destroy', function(){
$document.find('[id^=typeahead]').remove();
$document.unbind('click', dismissClickHandler);
});
I submitted a bug: https://github.com/angular-ui/bootstrap/issues/2551
When the user clicks a link, I want to execute some code in a function inside the controller. But I want to prevent that the URL changes.
I tried the following possibilities
Removed the href-attribute. Didn't work, still changes the url to '/'
Tried ng-click='deleteUser(user.id, $event)' and $event.preventDefault() in my deleteUser()-function. Didn't work.
What did work is a hack I've found on GitHub about an unintended reload.
This is how I do it now:
<a ng-click="deleteUser(user.id)" href="javascript:">Delete user</a>
Question
What is the'clean' method to prevent a link from changing the URL?
<a ng-click="deleteUser(user.id)" href="">Delete user</a>
If you look at the source code for the a element directive (which is a part of the Angular core), it states at line 29 - 31:
if (!element.attr(href)) {
event.preventDefault();
}
Which means Angular already is solving the issue of links without a href. The only issue you still have is the css problem. You can still apply the pointer style to anchors that have ng-clicks, e.g.:
a[ng-click] {
/* Styles for anchors without href but WITH ng-click */
cursor: pointer;
}
So, you could even make your site more accessible by marking real links with a subtle, different styling then links that perform functions.
Happy coding!
The real problem is in the a directive
That's right, every <a></a> element is actually an AngularJS directive.
It seems to fix some issues with IE if you look the comments in the code.
But everything for me is working great when I just removed the directive from the AngularJS core code.
I was having the same problem as you did and tried all of the other solutions. The difference is that I had the problem only in IE.
If you don't want to play with building the AngularJS script from source, just search for htmlAnchorDirective in the angular.js file and remove/comment it out.
I believe there is a bigger problem here which should be addressed in the AngularJS core, but I haven't found it yet.
UPDATE: This solution is most probably outdated now! You should try using the latest AngularJS version.
What exactly didn't work when you removed the href attribute?
That's exactly what you should do. See this fiddle for an example:
http://jsfiddle.net/terebentina/SXcQN/
As #Justus pointed out, if the source code is like:
if (!element.attr(href)) {
event.preventDefault();
}
Making element.attr(href) as null string '' should get you inside the if condition, as !'' evaluates to true. That is the solution by #umur
I have always been doing deleteUser($event,user.id) and it seemed to work. A possible problem would be the ordering of the variables to your click handler. The first argument should probably be the $event object.
I use my custom directive to accomplish this. Its mechanism is to operate ng-click directive itself.
angular.module('delete', [])
.directive('buttonDelete', ['$parse', function ($parse) {
var confirmFunc = function (scope, element, attr, event, ngClick) {
if (! confirm("Are you sure?")) {
event.preventDefault();
}
else {
// Copy from ngEventDirectives initialization.
var fn = $parse(ngClick);
scope.$apply(function() {
fn(scope, {$event:event});
});
}
};
return {
restrict: 'C',
compile: function (element, attr) {
var ngClick = attr.ngClick;
attr.ngClick = '';
return {
pre: function (scope, element, attr) {
element.click(function (e) {
confirmFunc(scope, element, attr, e, ngClick);
});
}
};
}
};
}]);
This is admittedly a hack, but I did:
<span class="link" ng-click="deleteUser(user.id)">Delete user</span>
and in my css had
span.link {
/* style like a link */
}
The following worked great for me:
<a ng-href="javascript: return false;" ng-click="alertSearchCtrl.deleteAlert()">Remove</a>
specifically, I'm AJAXing in some date ranges into a pair of SELECTs (maintained with an AngularJS ng-repeat), which I'm then turning into a slider using jQuery UI's selectToUISlider. I assume selectToUISlider's behavior is undefined if the SELECTs it's operating on are modified while it's running. is there a way to ensure that it is called only after AngularJS has finished updating? I haven't encountered any problems yet, but I'm not sure I'm just lucky, or haven't had my computer lag at just the right moment, etc...
I can think of two solutions, but neither seems very good:
don't use the ng-repeater; build the SELECTs with jQuery. but that'd be sad to have to do.
delay the call to selectToUISlider using setTimeout. but that seems... inelegant.
I don't know how selectToUISlider works, but you want a directive. In that directive, $watch for changes to the list and update the slider however it's supposed to be done.
http://docs.angularjs.org/api/ng.$rootScope.Scope#$watch
Example HTML:
<select jq-slider="myList" ng-options="item.val for item in myList"></select>
Example JS:
myApp.directive('jqSlider', function() {
return {
link: function(scope, elm, attrs) {
scope.$watch(attrs.jqSlider, function whenMyListChanges(newValue, oldValue) {
$(elm).applySelectUISliderUpdateForNewValues();
});
}
};
});