I have articles, that contain inner programming code.
I used angular-highlightjs for hilight code in frontend, such as:
<div hljs>
<!-- put your codes here -->
</div>
It works fine!
Now I include textAngular for CREATE/UPDATE articles in admin panel, but it erases my "hljs" directive from input articles.
What should I do to fix it? or suggest me angular wysiwyg with code highlight support.
UPD:
Thanks for advice,
this code work fine:
.config(function($provide){
$provide.decorator('taOptions', ['taRegisterTool', '$delegate', '$compile', '$rootScope', function(taRegisterTool, taOptions, $compile, $rootScope){
taRegisterTool('hljs', {
iconclass: "glyphicon glyphicon-eye-open",
tooltiptext: "code highlighting",
action: function() {
var selectedText = window.getSelection();
var hljsTag = '<div hljs>'+ selectedText +'</div>';
var scope = $rootScope.$new();
var element = $compile(hljsTag)(scope);
return this.$editor().wrapSelection('insertHTML', element.html(), true);
}
});
taOptions.toolbar[1].push('hljs');
return taOptions;
}]);
});
You can create your own toolbar button in textAngular for that like this:
module.config(function($provide){
$provide.decorator('taOptions', ['taRegisterTool', '$delegate', function(taRegisterTool, taOptions){
// $delegate is the taOptions we are decorating
// register the tool with textAngular
taRegisterTool('colourRed', {
iconclass: "fa fa-square red",
action: function(){
this.$editor().wrapSelection('forecolor', 'red');
}
});
// add the button to the default toolbar definition
taOptions.toolbar[1].push('colourRed');
return taOptions;
}]);
});
This button will make your selected content in textAngular editor red.
Go to https://github.com/fraywing/textAngular/wiki/Customising-The-Toolbar for more info
Related
Using AngularJS and Angular-UI Tooltip (uib-tooltip) to setup a tooltip system that allows the user to turn the tooltips on & off. I'd also like to keep the text in a central location for easy editing. I'm running into trouble, however, replicating the tooltip-enable portion of the uib-tooltip directive which toggles the on/off portion.
The standard approach.
<ul id="realmContainer" uib-tooltip="Even more stuffs" tooltip-placement="bottom" tooltip-enable="userService.data.current.preferences.activeTooltips">
...
My HTML
<ul id="realmContainer" tip>
The "tip" directive
(function () {
'use strict';
angular
.module('app.directives')
.directive('tip', ['$rootScope', 'userService', '$compile', Tooltip]);
/* #ngInject */
function Tooltip($rootScope, userService, $compile) {
return {
restrict: 'A',
priority: 10000,
terminal: true,
link: link
};
function link(scope, element, attrs) {
// lookup and assign the tooltip by ID
attrs.$set('uib-tooltip', dictionary[element[0].id]);
attrs.$set('tooltip-placement', attrs['tip-position'] || 'bottom');
// Remove the 'tip' attribute so we don't get stuck in a loop
attrs.$set('tip', null);
// compile the new HTML. This works so far
$compile(element)(scope);
//I just can't get this to recompile the html when the value changes
scope.userService = userService;
scope.$watch('userService.data.current.preferences.activeTooltips', function(newValue, oldValue){
var isVisible = newValue === undefined ? true : newValue;
// This sets true/false in the DOM
attrs.$set('tooltip-enable', isVisible);
// Mouseover event still triggers even after removing
// tooltip-enable. What gives?
$compile(element)(scope);
})
}
}
var dictionary = {
realmContainer: 'Even more stuffs'
}
})();
It seems like the tooltip always displays on mouseover. The $watch picks up the new value, but the $compile doesn't seem to remove the mouseover trigger from the DOM.
Any help would be appreciated.
I'm creating a project using NodeJS, Express and AngularJS that will have a search form (added via custom directive) and a search results that must be loaded only after the search button is pressed.
The problem is that the method I have created inside the controller can't be found from the search form.
Here is a sample of my code:
app.js
(function() {
var app = angular.module('app', ['app-directives']);
app.controller('AppController', function() {
this.buttonClick = function() {
alert('Test');
};
});
})();
directives.js
(function(){
var app = angular.module('app-directives', []);
app.directive('searchForm', function() {
return {
retrict: 'E',
templateUrl: '/partials/search-form.html'
};
});
app.directive('searchResults', function() {
return {
retrict: 'E',
templateUrl: '/partials/search-results.html'
};
});
})();
search-form.html
<input type="text" id="query" />
<button onclick="buttonClick">Search</button>
page-content.html
<section id="mainContent">
<search-form></search-form>
<search-results></search-results>
</section>
UPDATE
The second question will be posted in another thread.
About your first question:
You are using onclick attribute instead angular's 'ng-click' in the button search. This could be the problem. And do not forget to also add the 'ng-app' and 'ng-controller' tags. If not, your method will never be visible.
I also would recommend you to use $scope service instead of 'this' for attaching models and functions you later will use in your views.
Regards
I am looking for a way to obtain an iframe contentWindow object and post a message to it after some action of the user. My current solution does not feel ok with angular at all (especially accessing the DOM from the controller).
I have created a plunker demonstrating the issue:
http://plnkr.co/edit/aXh4jydWGWfK3QQD4edd
Is the a more angular way to execute the postMessage?
controller:
app.controller('Main', function($scope) {
$scope.click = function() {
var iframe = document.getElementById("inner").contentWindow;
iframe.postMessage("Hello iframe", '*');
}
});
html:
<body ng-controller="Main">
<button ng-click="click()">send message</button>
<iframe id="inner" src="inner.html"/>
</body>
I realize your question is over a year old at this point but I've recently had a similar need so I thought I'd post my solution. Originally I had something like you posted but as you pointed out this doesn't feel very "Angular". It's also not easily testable which I supposed is also not very "Angular".
Instead I've refactored my code to implement the iframe as a directive. I then $broadcast() events from my app's controllers and have the directive listen for them. This code can probably be improved quite a bit but it's feels a little more "Angular" and avoids directly touching the DOM.
'use strict';
angular.module('app')
.directive('angularIframe', ['$rootScope', function($rootScope) {
return {
restrict: 'E',
replace: true,
template: '<iframe id="game" src="/iframe/index.html" width="100%" height="100%" frameboarder="0" scrolling="no"></iframe>',
link: function(scope, elem) {
var off = $rootScope.$on('app.postmessage', function(ev, data, targetOrigin) {
var str = JSON.stringify(data);
targetOrigin = targetOrigin || '*';
elem[0].contentWindow.postMessage(str, targetOrigin);
});
// See: http://stackoverflow.com/a/14898795/608884
elem.on('$destroy', function() {
off();
});
}
};
}]);
You can then use this directive by adding <game></game> somewhere in your application.
In a controller you can now broadcast the app.postmessage event along with some data to invoke postMessage() on the iframe:
var myData = { foo: 'bar' };
$rootScope.$broadcast('app.postmessage', myData);
Using Angular, I'm trying to create a directive that will be placed on a button that will launch a search dialog. There are multiple instances of the search button, but obviously I only want a single instance of the dialog. The dialog should be built from a template URL and have it's own controller, but when the user selects an item, the directive will be used to set the value.
Any ideas on how to create the dialog with it's own controller from the directive?
Here's what I've go so far (basically just the directive)...
http://plnkr.co/edit/W9CHO7pfIo9d7KDe3wH6?p=preview
Here is the html from the above plkr...
Find
Here is the code from the above plkr...
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
var person = {};
person.name = 'World';
$scope.person = person;
$scope.setPerson = function(newPerson) {
person = newPerson;
$scope.person = person;
}
});
app.directive('myFind', function () {
var $dlg; // holds the reference to the dialog. Only 1 per app.
return {
restrict: 'A',
link: function (scope, el, attrs) {
if (!$dlg) {
//todo: create the dialog from a template.
$dlg = true;
}
el.bind('click', function () {
//todo: use the dialog box to search.
// This is just test data to show what I'm trying to accomplish.
alert('Find Person');
var foundPerson = {};
foundPerson.name = 'Brian';
scope.$apply(function () {
scope[attrs.myFind](foundPerson);
});
});
}
}
})
This is as far as I've gotten. I can't quite figure out how to create the dialog using a template inside the directive so it only occurs once and then assign it a controller. I think I can assign the controller inside the template, but first I need to figure out how to load the template and call our custom jQuery plugin to generate the dialog (we have our own look & feel for dialogs).
So I believe the question is, how do I load a template inside of a directive? However, if there is a different way of thinking about this problem, I would be interested in that as well.
I will show you how to do it using bootstrap-ui. (you can modify it easily, if it does not suit your needs).
Here is a skeleton of the template. You can normally bound to any properties and functions that are on directive's scope:
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
... // e.g. <div class="button" ng-click=cancel()></div>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
...
</div>
</div>
</div>
Here is how to create/declare directive in your module:
.directive("searchDialog", function ($modal) {
return {
controller: SearchDialogCtrl,
scope : {
searchDialog: '=' // here you will set two-way data bind with a property from the parent scope
},
link: function (scope, element, attrs) {
element.on("click", function (event) { // when button is clicked we show the dialog
scope.modalInstance = $modal.open({
templateUrl: 'views/search.dialog.tpl.html',
scope: scope // this will pass the isoleted scope of search-dialog to the angular-ui modal
});
scope.$apply();
});
}
}
});
Then controller may look something like that:
function SearchDialogCtrl(dep1, dep2) {
$scope.cancel = function() {
$scope.modalInstance.close(); // the same instance that was created in element.on('click',...)
}
// you can call it from the template: search.dialog.tpl.html
$scope.someFunction = function () { ... }
// it can bind to it in the search.dialog.tpl.html
$scope.someProperty;
...
// this will be two-way bound with some property from the parent field (look below)
// if you want to perform some action on it just use $scope.$watch
$scope.searchDialog;
}
Then it your mark-up you can just use it like that:
<div class="buttonClass" search-dialog="myFieldFromScope">search</div>
I recommend this plugin:
https://github.com/trees4/ng-modal
Demo here:
https://trees4.github.io/ngModal/demo.html
Create a dialog declaratively; and it works with existing controllers. The content of the dialog can be styled however you like.
I am having an issue in Angularjs where there is a flicker in my HTML before my data comes back from the server.
Here is a video demonstrating the issue: http://youtu.be/husTG3dMFOM - notice the #| and the gray area to the right.
I have tried ngCloak with no success (although ngCloak does prevent the brackets from appearing as promised) and am wondering the best way to hide content until the HTML has been populated by Angular.
I got it to work with this code in my controller:
var caseCtrl = function($scope, $http, $routeParams) {
$('#caseWrap').hide(); // hides when triggered using jQuery
var id = $routeParams.caseId;
$http({method: 'GET', url: '/v1/cases/' + id}).
success(function(data, status, headers, config) {
$scope.caseData = data;
$('#caseWrap').show(); // shows using jQuery after server returns data
}).
error(function(data, status, headers, config) {
console.log('getCase Error', arguments);
});
}
...but I have heard time and time again not to manipulate the DOM from a controller. My question is how can I achieve this using a directive? In other words, how can I hide the element that a directive is attached to until all content is loaded from the server?
In your CSS add:
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
and just add a "ng-cloak" attribute to your div like here:
<div id="template1" ng-cloak>{{scoped_var}}<div>
doc: https://docs.angularjs.org/api/ng/directive/ngCloak
On your caseWrap element, put ng-show="contentLoaded" and then where you currently have $('#caseWrap').show(); put $scope.contentLoaded = true;
If the caseWrap element is outside this controller, you can do the same kind of thing using either $rootScope or events.
Add the following to your CSS:
[ng\:cloak],[ng-cloak],.ng-cloak{display:none !important}
The compiling of your angular templates isn't happening fast enough.
UPDATE
You should not do DOM manipulation in your controller. There are two thing you can do...
1. You can intercept changes to the value within the scope of the controller via a directive! In your case, create a directive as an attribute that is assigned the property you want to watch. In your case, it would be caseData. If casedata is falsey, hide it. Otherwise, show it.
A simpler way is just use ngShow='casedata'.
Code
var myApp = angular.module('myApp', []);
myApp.controller("caseCtrl", function ($scope, $http, $routeParams, $timeout) {
$scope.caseData = null;
//mimic a delay in getting the data from $http
$timeout(function () {
$scope.caseData = 'hey!';
}, 1000);
})
.directive('showHide', function () {
return {
link: function (scope, element, attributes, controller) {
scope.$watch(attributes.showHide, function (v) {
if (v) {
element.show();
} else {
element.hide();
}
});
}
};
});
HTML
<div ng-controller='caseCtrl' show-hide='caseData'>using directive</div>
<div ng-controller='caseCtrl' ng-show='caseData'>using ngShow</div>
JSFIDDLE:http://jsfiddle.net/mac1175/zzwBS/
Since you asked for a directive, try this.
.directive('showOnLoad', function() {
return {
restrict: 'A',
link: function($scope,elem,attrs) {
elem.hide();
$scope.$on('show', function() {
elem.show();
});
}
}
});
Stick (show-on-load) in your element, and in your controller inject $rootScope, and use this broadcast event when the html has loaded.
$rootScope.$broadcast('show');
I have used Zack's response to create a 'loading' directive, which might be useful to some people.
Template:
<script id="ll-loading.html" type="text/ng-template">
<div layout='column' layout-align='center center'>
<md-progress-circular md-mode="indeterminate" value="" md-diameter="52"></md-progress-circular>
</div>
</script>
Directive:
directives.directive('loading', function() {
return {
restrict: 'E',
template: 'll-loading.html',
link: function($scope,elem,attrs) {
elem.show();
$scope.$on('loaded', function() {
console.log("loaded: ");
elem.hide();
});
}
}
});
This example uses angular-material in the html
The accepted answer didn't work for me. I had some elements that had ng-show directives and the elements would still show momentarily even with the ng-cloak. It appears that the ng-cloak was resolved before the ng-show returned false. Adding the ng-hide class to my elements fixed my issue.