0

Howdie do,

So we have the following controller:

'use strict';

angular.module('24SevenWse')
  .controller('NavbarCtrl', ['$scope', 'dataFactory', function ($scope, dataFactory) {
      $scope.user = dataFactory.getUser();
      $scope.code = dataFactory.getCode();
      }
      var companyLink = angular.element('<link rel="stylesheet" href="http://localhost/~jw1050/css/$scope.code.css">');
      angular.element('head').append(companyLink);


  }]);

As you can see, I'm appending a new style sheet to the head element on the page. Now, when I hard code the value such as:

var companyLink = angular.element('<link rel="stylesheet" href="http://localhost/~jw1050/css/ABC.css">');

However, I'm attempting to load a new image via CSS based upon the code the user logs into the software with.

Now, the view that this is for is below:

<nav class="navbar navbar-fixed-top" ng-controller="NavbarCtrl">
  <div class="container-fluid">
        <div class="navbar-header pull-left">
          <a class="navbar-brand tracking-navbar-brand newImage">
              <img id="custLogo">
          </a>
        </div>
      </div>
</nav>

The .css file that is being injected into the head just contains the following:

#custLogo {
    content: url("http://localhost/~jw1050/logos/logo.png");
}

The .css files will each be named after the code a user can login with. For example, user logs in with the code ABC. That code would correspond directly to the file ABC.css

So I need to pass the code via the controller to the var companyLink so that the style sheet that is appended to the head of the document will be:

<link rel="stylesheet" href="http://localhost/~jw1050/css/ABC.css">

Now I've tried the following in the controller:

var companyLink = angular.element('<link rel="stylesheet" href="http://localhost/~jw1050/css/{{code}}.css">');
var companyLink = angular.element('<link rel="stylesheet" href="http://localhost/~jw1050/css/'{{code}}'.css">');

Neither seem to work. My thinking is the link that I'm appending to the head is part of the view. So it should be able to pass the code in the controller to view, but that doesn't seem to work.

Any ideas?

Jimmy
  • 887
  • 1
  • 10
  • 24
  • why not just use inline styles if the css you're loading has a single declaration? – Neil S Sep 18 '15 at 17:03
  • As we're exploiting the CSS ability to fail up to other sheets. So if a code doesn't have a corresponding code, it will fail up to the default one – Jimmy Sep 18 '15 at 18:10
  • You could still do the same, using ng-attr for the inline style – Neil S Sep 18 '15 at 18:27
  • I agree with you, but say only one client wants to change some theme aspect, we would just have to go to their CSS file and change it in one place. This is the main reason to use the a full CSS file. Allows for easier future updates – Jimmy Sep 18 '15 at 18:30

2 Answers2

1

Try this:

var companyLink = angular.element('<link rel="stylesheet" href="http://localhost/~jw1050/css/'+$scope.code+'.css">');
Marik
  • 95
  • 8
  • While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – ryanyuyu Sep 18 '15 at 18:12
  • Thank you VERY much @ryanyuyu . I didn't even think about concatenating the variable into the string. THANK UUU!! – Jimmy Sep 18 '15 at 18:17
  • Actually, the question is about the syntax... not much to comment on the topic. – Marik Sep 18 '15 at 18:39
1

Generally you want to avoid putting DOM manipulation in controllers, but I'm just going to skip that lecture and go on with the answer.

I'm assuming $scope.code.css has the string value of ABC, for instance.

You are passing in a string to angular.element so just build a string using the + operator.

var yourString = '<link rel="stylesheet" href="http://localhost/~jw1050/css/' + 
                 $scope.code.css + '">';

angular.element(yourString);

I didn't test this, but as far as I can tell this should work. You don't even have to create a variable you can just inline it inside the parenthesis of the angular.element call (although I think that gets hard to read real quick).

If the sole purpose of this code is just to change the logo, I think there are better ways to do it. Using a directive and passing in a url to it is not a bad idea (see something similar here angularjs: ng-src equivalent for background-image:url(...)). This way you contain DOM manipulation to the directive, and in the controller you can just deal with fetching data (via a service/factory of course), binding it to a scope variable and passing it to the directive.

Community
  • 1
  • 1
JesseDahl
  • 137
  • 3
  • 7
  • Thank you very much @JesseDahl. The reason I'm not doing this in a custom directive is in the future, we will be changing the entire theme and not just the back ground image. If you have a link to the lecture you skipped about avoiding DOM manipulations in controllers, I'm more than happy to read – Jimmy Sep 18 '15 at 18:15
  • After doing some research, I see what you mean. The controller is just supposed to be the link between the Model and View. It should be pretty stupid. I'm going to look into converting this to a directive. Thanks again @JesseDahl – Jimmy Sep 18 '15 at 18:35
  • Controller bloat is a pretty common pitfall in AngularJS, so whereever possible extract logic and non viewmodel stuff out into some kind of provider. I find myself rarely even using DOM manipulation at all in AngularJS. It's good to think in a different way then say, using jquery and listening for events to do DOM manipulation. Instead, focus on data. It controls everything and drives behavior of UI controls (binding show/hide to a boolean value or function, f'instance). There's times where you may need to get back to DOM manipulation but they're few and far between. – JesseDahl Sep 19 '15 at 23:03
  • If the themes already exist in your css, you can use the ng-class directive to handle a lot of the logic of switching between themes (allowing you to bind to controller scope vars). I haven't done any dynamic loading of css but i'm sure there's many ways to skin that cat. Probably unless you're letting the user submit custom themes, then loading it all at once at the beginning is best. – JesseDahl Sep 19 '15 at 23:23
  • I actually wrote it the way you're describing initially. I had a scope variable set and based off that variable, I would call ng-class in order to switch the theme/logo. However, I was told to code the application so that the CSS files are injected into the DOM once a page is viewed. That way should the injection not work, it will fail up to the next CSS file – Jimmy Sep 20 '15 at 15:26
  • I'm kinda confused on what you're trying to do. Are users submitting "themes" by uploading css? If not, I don't really see a great reason to load css dynamically. – JesseDahl Sep 21 '15 at 07:56
  • No, users aren't submitting themes. They are submitting logos currently, but in the future, they will be submitting theme changes. I'm 100% with you that it would be easier to just use angular to change the theme, however, I've been overruled on this. The boss wants to dynamically inject the CSS files – Jimmy Sep 21 '15 at 13:32