Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Icons should be added via CSS #245

Open
slavafomin opened this issue Mar 19, 2015 · 14 comments · May be fixed by #246
Open

Icons should be added via CSS #245

slavafomin opened this issue Mar 19, 2015 · 14 comments · May be fixed by #246

Comments

@slavafomin
Copy link

Right now icons are added to buttons as character symbols:
https://github.com/isteven/angular-multi-select/blob/master/isteven-multi-select.js#L898-L900

This is a limitation.

Actually, the visual part of the component should be controlled with CSS for ease of customization.

I will try to do a PR on this.

@slavafomin slavafomin linked a pull request Mar 19, 2015 that will close this issue
@slavafomin
Copy link
Author

Please see the PR.

I've removed icons from JS and added them via :before pseudo-element in CSS.

@isteven
Copy link
Owner

isteven commented Mar 20, 2015

Hi @slavafomin ,

I put the icons there in the code so people can easily use HTML tags if they want to (For example, using font-awesome, Bootstrap's glyphicon, or perhaps a custom image if they want to).

@slavafomin
Copy link
Author

Icons actually are not in HTML template, they are in the JavaScript code, which is a bad practice. We should try to separate things as much as possible. Especially, we shouldn't mix business logic of the component with it's presentation.

And, by the way, we can use FontAwesome pretty easy using CSS, we don't actually need to use explicit elements like span.fa.fa-icon-name. This can be achieved using SASS or LESS. And if the user will decide to add icon elements directly to the template he will be able to override the template and add new elements explicitly.


If you were talking about adding icons by means of specifying translation string with HTML components in it:

  1. It won't work currently (cause pre-defined icon is always appended to the translation string).
  2. We will end up with mixed concepts again (we shouldn't mix translation with presentation).

@isteven
Copy link
Owner

isteven commented Mar 25, 2015

Hi @slavafomin ,

Your idea is conceptually correct. Do you have a suggestion on how to do this in practice?

The goal is to:

  • Still allowing users to define their own style and icon (be it image, font awesome etc)
  • Library agnostic, using only AngularJs and nothing else.
  • Directory / folder agnostic.

@slavafomin
Copy link
Author

Hey @isteven.

I think the first order of business is to remove icon-related code completely from JS and move it to CSS and/or to HTML.

Please see my PR #246 — I've removed icons from JS and moved it to CSS. I've had to add some CSS classes to buttons in order to better control it from CSS side.

I think it achieves the desired goals:

  1. Users can define their own icons either by overriding CSS styles or by overloading the entire template.
  2. I've not added any dependencies.
  3. What do you mean by directory agnostic? I think this problem has nothing to do with filesystem structure cause all paths are controlled by CSS.

If you will agree to accept the PR I will be glad to write small documentation on how to use custom icons.

@isteven
Copy link
Owner

isteven commented Mar 25, 2015

Hi @slavafomin ,

Correct me if I'm wrong - the CSS solution you mentioned works on Unicode icons. What if a user want to use font-awesome, or bootstrap's glyphicon, or custom image, or no icons at all?

@slavafomin
Copy link
Author

Not using icons at all is easy, you will just need to add content: ''; to your CSS.

If you want to use FA icons you have several options:

  1. If you are using vanilla CSS you can just copy icon definitiion from provided FA's CSS file and add it to the button via some pseudo-selector, e.g. :before in your CSS. This will work, but it's not DRY and increases the size of CSS file. Also it will break future compatibility with FA. I will recommend to avoid this approach if possible.
  2. If you are using some CSS compiler like SASS/Compass or LESS (and you definitely should!) you can easilly include FA's mixins to your CSS file. This will help you to avoid DRY problem as well as future compatibility problem. This is a pretty solid approach.
  3. You can overload the component template and explicitly add FA's elements to the HTML. This will give you the highest possible level of customization and will mitigate all mentioned problems.

Also, we can split component's template into several smaller templates. That way user will not have to overload the entire template, just some part of it.

@isteven
Copy link
Owner

isteven commented Mar 25, 2015

@slavafomin ,

Thanks for the ideas - you do have pretty solid knowledge in CSS 👍

I personally don't prefer solution 1) for the same reason that you mentioned. It's really not practical for both short and long term.

Solution 2) is ok, but then again I want the directive to be library agnostic (this has been one of the primary goals of the directive since day 1).

This leaves us with option 3), that is overloading the template. Like you said, this will allow the user to customize things to the highest level, and avoid all the problems. But tell me, is it practical for the users? I'm an old school developer here, and usually, if I want to modify small things like icons, I'll straight away open the code (be it HTML template, CSS or JS), search the thing I want to change, update and save. I don't have to write & inject any extra code etc. What is the effort to overload template (as in doing it AngularJs way), to get the result that we want (in this case, changing the icons)?

@slavafomin
Copy link
Author

I think you've misunderstood no. 2.

I'm not asking you to add CSS to the library. I was speaking about the end-user. She will be able to customize the library buttons by including FA's mixins in her CSS. No need to touch the library or to overload the template. I think this is a compromised solution.

Considering option No. 3, if you prefer, we can add explicit icon-elements to the default HTML template. The end user will be able to just replace classes for this elements to make it FA or something else.

E.g. we can have such button in default template:

<button class="button button-select-all" type="button">
    <span class="icon icon-select-all"></span>
    {{ selectAllTitle }}
</button>

User will be able to use FA icon by replacing it with:

<button class="button button-select-all" type="button">
    <span class="fa fa-select-all"></span>
    {{ selectAllTitle }}
</button>

The difference will be in class="icon icon-select-all" vs class="fa fa-select-all".

Or, we can even add configuration option to override icon classes, e.g.:

var defaultIcons = {
  selectAll: 'icon icon-select-all',
  selectNone: 'icon icon-select-none',
  // ...
};

User will be able to override those:

<div
    isteven-multi-select
    icon-classes="myIconClasses"
>
</div>
$scope.myIconClasses = {
  selectAll: 'fa fa-select-all',
  selectNone: 'fa fa-select-none',
  // ...
};

And the template will be:

<button class="button button-select-all" type="button">
    <span class="{{ iconClasses.selectAll }}"></span>
    {{ selectAllTitle }}
</button>

I think I will be able to make a PR for this if you'd like.

@nathanboktae
Copy link

+1 for keeping styling concerns in CSS. Then users can use font icons, background images as raster or SVGs, etc. as the choose.

@brycehewett
Copy link

+1 for keeping the icons in css.

@Amenel
Copy link

Amenel commented Jan 7, 2016

This is a sound proposal that adds value to the library without removing anything. Has the PR been merged?

@jeroenheijmans
Copy link

jeroenheijmans commented May 24, 2016

I was about to open a similar issue, as our designer had effectively forked the lib merely for the purpose of changing the icons.

How about an approach similar to how you've done the "translation" bit? Allow me to express my suggestion in (pseudo)code:

$scope.icon        = {};
if (typeof attrs.iconCustomization !== 'undefined') {
    $scope.icon.selectAll       = $sce.trustAsHtml( $scope.iconCustomization.selectAll );
    $scope.icon.selectNone      = $sce.trustAsHtml( $scope.iconCustomization.selectNone );
    $scope.icon.reset           = $sce.trustAsHtml( $scope.iconCustomization.reset );
    $scope.icon.tickMark        = $sce.trustAsHtml( $scope.iconCustomization.tickMark );
} else {
    $scope.icon.selectAll       = '&#10003;';    // a tick icon
    $scope.icon.selectNone      = '&times;';     // x icon
    $scope.icon.reset           = '&#8630;';     // undo icon            
    $scope.icon.tickMark        = '&#10003;';    // a tick icon 
}

I've used / mimicked the existing style of the lib with the above, making it analogous to the translation section.

Obviously the iconCustomization should be bound on the scope as well.

This allows users to override the default html entities with either other entities, tags with icons in a font of their choosing, or heck: even img tags.

PS. If a change like this happens, the hard-coded &nbsp;&nbsp; bits on the translation may also have to be dealt with: our use-case was to set the icons to nothing at all (empty strings), but then those two non-breaking spaces will still be rendered, causing awkward alignment. For that I'd suggest changing the translation bit so that it special-cases falsy icon settings (for backwards compatability; if you can do breaking changes removing the hard-coded non-breaking spaces in favor of a css-based solution would be preferred).

jeroenheijmans added a commit to omniaretail/angular-multi-select that referenced this issue May 25, 2016
Fixes isteven#245 in original repository.

After this change the user can fully customize the "icons", replacing
the default html entity characters by any string, including:

- Different html entities or unicode characters;
- Bits of html offloading things to a icon font;
- Html img tags;
- Empty strings (that effectively removes the icons);

The change is backwards compatible, only "activated" if the element that
uses this directive also has a `custom-icon` attribute. That attribute
works analogous to the `translation` attribute. Backwards compatability
is the reason for the somewhat convoluted "pad-with-nbsp" function, that
might be removed in a future major release.
@jeroenheijmans
Copy link

jeroenheijmans commented May 25, 2016

In abovementioned pull request my (currently) preferred/used approach is shown. Usage is pretty simple:

<span isteven-multi-select custom-icon="myIconData" ...></span>

And in your scope or controller declare the data:

scopeOrController.myIconData = {
    selectAll       : "", // Just a label
    selectNone      : "<strong>X</strong>",
    reset           : "<i class='fa fa-recycle'></i>", // FontAwesome example
    tickMark        : "&#xE5CA"  // Different tick mark
}

Html with glyphicons or font-awesome icons is supported, as is "removing" icons by setting them to empty strings.

PS. I do think a more css-oriented solution might be preferred, but the above PR aims to be (a) backwards compatabile and (b) in line with the current code/translation style, to make it easier to use it right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants