Optimizing AngularJS directive that updates ng-model and ng-style on focus - events

I'm new to AngularJS and I'm making made a couple of custom Angular directives to do what I used to do with Jquery, however there is one case where I'm not sure if I'm doing it the "the angular way". It works but I think there might be a better way.
I want to do is this for a search box:
When focus is on the search box the app must change the color of the text in the box from grey to black. The app must also then check the current text in the box, if it is the default text then the app must clear the text.
When the box loses focus (blur) the app must change the box's text back to grey. It must then put back the default text only if the text box is empty upon losing focus.
Here is a jsfiddle that has a directive set up to do all of this perfectly.
http://jsfiddle.net/Rick_KLN/5N73M/2/
However I suspect there is an even better way to do it.
It seems like all three those variables in the controller should be unnecessary.
I also seems like having 4 if, else statements is too much and that binding to all the events is overkill seeing as only focus and blur are used and they are specified in the if statements.
Any ideas on optimizing this directive?

The "default text" behavior you are looking for is automatically handled by the HTML5 placeholder attribute. It is supported in just about any modern browser, and can be styled using CSS, as follows:
Markup:
<input id="searchBar" type="text" placeholder="Search" />
CSS:
#searchBar { color: #858585; }
#searchBar:focus { color: #2c2c2c; }
#searchBar:focus::-webkit-input-placeholder { color: transparent; }
#searchBar:focus::-moz-placeholder { color: transparent; }
#searchBar:focus:-moz-placeholder { color: transparent; }
#searchBar:focus:-ms-input-placeholder { color: transparent; }
It's that simple.
Notes:
The pseudo-elements & pseudo-classes (-webkit-input-placeholder, etc) are what hide the placeholder text on focus. Normally it stays until you start typing.
I forked your original jsFiddle. It's not really an AngularJS app anymore:
http://jsfiddle.net/Smudge/RR9me/
For older browsers: You can still use the same code as above, but you could use Modernizr (or something similar) to fall-back to a javascript-only approach if the attribute is not supported.

You can create a custom directive that requires the ng-model directive and then within your directive's link function supply a fourth parameter that is a reference to the model. This will allow you to watch the model for changes and react accordingly. Here is the fiddle:
http://jsfiddle.net/brettlaforge/6t39j/3/
var app = angular.module('app', []);
app.directive('searchbar', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, model) {
var options = scope.$eval(attrs.searchbar);
scope.$watch(attrs.ngModel, function(value) {
// If the input element is currently focused.
if (!elm.is(":focus")) {
// If the input is empty.
if (value === undefined || value === "") {
// Set the input to the default. This will not update the controller's model.
elm.val(options.default);
}
}
});
elm.on('focus', function(event) {
// If the input is equal to the default, replace it with an empty string.
if (elm.val() === options.default) {
elm.val('');
}
});
elm.on('focusout', function(event) {
// If the input is empty, replace it with the default.
if (elm.val() === '') {
elm.val(options.default);
}
});
}
};
});
function FormCtrl($scope) {
$scope.search = "";
}​

Related

Telerik Words Processing - No line strike through from HTML to PDF

I am working with Telerik Word Processing (WP) and in some instances the HTML output on screen has a line strike through to show that an event is cancelled.
Because of how the WP works, it cannot use CSS in the standard way using links and relative paths so am using style tags in the CSHTML file.
If in the page I use
.cancelled-event {
color: #c82333;
text-decoration: underline !important
}
The text is underlined and is coloured correctly, if I use
.cancelled-event {
color: #c82333;
text-decoration: line-through !important
}
I just get the text the right colour.
Overline also does not work, however only tested this to ensure that Im not being an idiot (doesn't mean Im not, but still one of the easy checkables)
What I would like help with is,
Has anyone else experienced this? If so how did you resolve it,
What other suggestions, is there to get
The CSHTML page is as below, munis code that will bloat this question.
<style>
.date-selection {
border: 1px solid #8c8c8c;
background-color: #ffffff
}
.cancelled-event {
color: #c82333;
text-decoration: line-through !important
... more styles here...
}
</style>
<img src="http://localhost:8001/images/logo.png" />
<br/>
<partial name="~/Views/Roster/_RosterAgenda.cshtml" model="#Model" />
I konw the strike through does show in 2/3 scenarios.
In view - works
In view where export should be as I have an exit where I can push the data to a view before pdf - works
In PDF - doesnt work.
PDF Generation is being done like this, the byte array that is passed in is base 64 encoded as the original file information is being passed from one System to an API over the wire.
public byte[] ConvertHtmlToPdf(byte[] fileData, string extension, PageSettings.PageOrientation orientation)
{
byte[] convertedData = null;
var base64EncodedBytes = Convert.FromBase64String(Encoding.Default.GetString(fileData));
var html = Encoding.UTF8.GetString(base64EncodedBytes);
HtmlFormatProvider htmlProvider = new HtmlFormatProvider();
RadFlowDocument document = htmlProvider.Import(html);
IFormatProvider<RadFlowDocument> provider = this.providers
.FirstOrDefault(p => p.SupportedExtensions
.Any(e => string.Compare(extension, e, StringComparison.InvariantCultureIgnoreCase) == 0));
if (provider == null)
{
Log.Error($"No provider found that supports the extension: {extension}");
return null;
}
var quality = Telerik.Windows.Documents.Fixed.FormatProviders.Pdf.Export.ImageQuality.Medium;
PdfFormatProvider formatProvider = new PdfFormatProvider();
formatProvider.ExportSettings.ImageQuality = quality;
if (document.Sections.Any())
{
foreach (var section in document.Sections)
{
//section.PageOrientation = orientation == PageSettings.PageOrientation.Landscape ? PageOrientation.Landscape : PageOrientation.Portrait;
section.Rotate(orientation == PageSettings.PageOrientation.Landscape ? PageOrientation.Landscape : PageOrientation.Portrait);
}
}
using (var stream = new MemoryStream())
{
formatProvider.Export(document, stream);
convertedData = stream.ToArray();
}
return convertedData;
}
I found a better, easier, nicer way, but this only works if you have the Kendo Tools license too.
$(".export-pdf").click(function() {
// Convert the DOM element to a drawing using kendo.drawing.drawDOM
kendo.drawing.drawDOM($(".content-wrapper"))
.then(function(group) {
// Render the result as a PDF file
return kendo.drawing.exportPDF(group, {
paperSize: "auto",
margin: { left: "1cm", top: "1cm", right: "1cm", bottom: "1cm" }
});
})
.done(function(data) {
// Save the PDF file
kendo.saveAs({
dataURI: data,
fileName: "HR-Dashboard.pdf",
proxyURL: "https://demos.telerik.com/kendo-ui/service/export"
});
});
});
As per usual Telerik documentation is awful, and to find anything you want you almost have to start looking for something else. However, this code was found at
https://www.telerik.com/blogs/5-ways-export-asp-net-word-pdf-file
The benefit of this, and once again this only works if you have UI for xxx. In this instance I am using UI for ASP.Net Core and also using Typescript which needed a modification to the definately typed file kendo.all.d.ts too.
function drawDOM(element: JQuery, options: any): JQueryPromise<any>; //Existing code in the d.ts file
function drawDOM(element: JQuery<HTMLElement>);
function drawDOM(element: any, options?: any): JQueryPromise<any>;
But this is \ was down to not passing in a type of jquery object of HTMLElement. This makes it a little more robust enabling you to pass more into it.
I suspect that this answer will only be of use to a small number of people, however, hopefully this will help someone in the future.

Kendo Grid validation message position issue

The Kendo grid I developed has a validation message, but the arrow points to the column to the right. I cannot change anything in /kendo.default.min.css as this is located in a shared folder which should not be changed. Any help on this?
dataSource: {
data: data.ReportData,
schema: {
model: {
fields: {
ProposedDiscount: {
validation: {
required: true,
proposeddiscountcvalidation: function (input) {
if (input.val() != "" && input.is("\[name='ProposedDiscount'\]")) {
input.attr("data-proposeddiscountcvalidation-msg", "Should be whole number between 0 & 100");
// $('.k-widget k-tooltip k-tooltip-validation k-invalid-msg .k-icon k-warning .k-tooltip-validation .k-callout-n').removeClass('.k-callout-n');
return input.val() >= 0 && input.val() < 101 && input.val() % 1 == 0;
} else {
return true;
}
}
}
}
You could try simply overriding some of the styles on the validation tool-tip. This works for me, though I've scoped it pretty tight to try to avoid any unexpected effects elsewhere. You might need to modify it slightly, depending on what version of kendo you're using:
<style>
.k-grid .k-grid-content tr.k-grid-edit-row>td[role='gridcell'] .k-tooltip-validation>.k-callout-n {
left: auto;
margin-left: auto;
}
</style>
Edit: I've just noticed you said you "cannot change anything in /kendo.default.min.css" - you shouldn't need to. This should override the default styles provided by kendo in that file. If you've got your own site-wide CSS file you could add it to that, or even just add it directly to the page hosting your grid (though that's not really recommended). Hope this helps.
The Kendo style default displays the tooltip and places the callout (arrow) in the center of the tooltip. If the message is wide enough, like in your example, because the arrow is in the center it ends up pointing to the wrong cell. If you constrain the tooltip to the width of the cell it will wrap the message and keep it constrained to the cell width, which means the centered arrow will line up.
.k-validator-tooltip { width: min-content; }

KendoUI dialog service change title color

Is there anyway to change the color of the dialog window when using the kendo dialog service?
Currently it defaults to red but I need to customize the window to show a different color based on what is passed.
I tried using a kendo-dialog as my template but it doesn't show the action buttons.
<kendo-dialog title="{{title}}" (close)="Cancel()" [ngClass]="yellow">
</kendo-dialog>
I asked myself that same question a while ago and came up with a solution found in this post : Kendo UI angular DialogService - Change the title bar background color
I'll copy my answer here:
I worked a solution for this. It works but it is not elegant one bit.
Here's the plunker link that demonstrates the code :
http://plnkr.co/edit/MGw4Wt95v9XHp9YAdoMt?p=preview
Here's the related code in the service:
const dialog: DialogRef = this.dialogService.open({
actions: message.actions,
content: MessageComponent,
title: message.title
});
const messageComponent = dialog.content.instance;
messageComponent.message = message;
//I get the dialog element and use jQuery to add classes to override styles.
//Let's say I had the error class as well.
const element = dialog.dialog.location.nativeElement;
$( element ).addClass( 'kendo-override ' + message.classes );
return dialog.result;
And the scss:
$error: #c13;
$success: #0c5;
.kendo-override {
&.error {
kendo-dialog-titlebar {
background-color: $error;
}
}
&.success {
kendo-dialog-titlebar {
background-color: $success;
}
}
}

CKEditor remove inline img style

I am using a responsive image technique setting a max-width of 100% with CSS.
This isn't working for any images added through CKEditor, as an inline style is added.
In CSS I have added a style to override the width, which works, but height: auto doesn't, so the images is stretched.
I need to find a way to stop CKEditor from adding the inline style in the first place.
I am using CKEditor 4.x
Thank you
A far better alternative to the accepted answer is to use disallowedContent (see docs), as opposed to allowedContent.
Using allowedContent requires you to create a rather large white-list for every possible tag or attribute; where as disallowedContent does not; allowing you to target the styles to ignore.
This can be done like so:
CKEDITOR.replace( 'editor1', {
disallowedContent: 'img{width,height};'
});
Since version 4.1, CKEditor offers so called Content Transformations and already defines some of them. If you restrict in your config.allowedContent that you don't want to have width and height in <img> styles, then editor will automatically convert styles to attributes. For example:
CKEDITOR.replace( 'editor1', {
allowedContent:
'img[!src,alt,width,height]{float};' + // Note no {width,height}
'h1 h2 div'
} );
then:
<p><img alt="Saturn V carrying Apollo 11" class="left" src="assets/sample.jpg" style="height:250px; width:200px" /></p>
becomes in the output:
<p><img alt="Saturn V carrying Apollo 11" height="250" src="assets/sample.jpg" width="200" /></p>
and, as I guess, it completely solves your problem.
You can listen to instanceReady event and alter any element before saving, in your case the img tag
CKEDITOR.on('instanceReady', function (ev) {
ev.editor.dataProcessor.htmlFilter.addRules(
{
elements:
{
$: function (element) {
// check for the tag name
if (element.name == 'img') {
var style = element.attributes.style;
// remove style tag if it exists
if (style) {
delete element.attributes.style;
}
}
// return element without style attribute
return element;
}
}
});
});

AngularJS : router : load view manually from within controller

Is there a way of manually loading the view from within the controller, after say some animation was triggered first? The scenario I have is the previous page content sliding up, after that the view would be updated when being off-the screen and once ready - slides back down with the new view from the new controller.
I've got already the router set up, but it just instantly replaces the view whenever the new controller is called.
Any fiddle if possible please?
Code in Controller shouldn't manipulate DOM, directives should. Here is directive to prevent preloading content of element with "src" (by browser's parser) and show content of element only after loading, and before loading show splash with spinner:
directive('onloadSrc', function($compile) {
return function(scope, element, attrs) {
element.bind('load', function() {
var parent = $compile(element[0].parentElement)(scope);
if (!element.attr('src') && attrs.onloadSrc) {
element.attr("src", attrs.onloadSrc);
// replace this dirty hardcode with your template for splash spinner
var spinner_div = $compile('<div style="z-index: 100; width: '+element.attr('width')+'px; height: '+element.attr('height')+'px; display:block; vertical-align:middle;"><img src="/img/spinner.gif" style="position: absolute; left: 50%; top: 50%; margin: -8px 0 0 -8px;"/></div>')(scope);
attrs.onloadSrc = "";
parent.prepend(spinner_div);
element.css("display", 'none');
attrs.xloading = spinner_div;
}
else {
if (attrs.xloading) {
attrs.xloading.remove();
attrs.xloading = false;
element.css("display", 'block');
}
}
}
);
}});
To use this directive, leave empty attribute src of element and fill attribute onload-src.
Angular has animations build in in unstable branch, which should perfectly fit your scenario.
Just check out http://www.nganimate.org/angularjs/tutorial/how-to-make-animations-with-angularjs.
ng-view directive has build in 'enter' and 'leave' animations.
Check you this sample: http://jsfiddle.net/nFhX8/18/ which does more less what you'd like to achieve.

Resources