9

I am struggling with my page that can't load properly. I am using a simple header-body-footer structure in html5 and CSS3.

    +----------+
    |  HEADER  |
+---+----------+---+
|       BODY       |
+---+----------+---+
    |  FOOTER  |
    +----------+

What I am doing right now is create a svg with D3 inside the body space, reading width and height dynamically after window is loaded (and pictures also).

Now I want to add angular to avoid code redundancy inside each page of the site and I did this:

(function() {
    var app = angular.module('neo4art', []);

    var pages = {
            "genesis.html": "The genesis of the project",
            "about.html": "About Us",
            "team.html": "The Team",
            "index.html": "Traversing Art Through Its Connections"
    }

    app.directive("header", function() {
        return {
            restrict : 'E',
            templateUrl : 'header.html'
        };
    });
    app.directive("footer", function() {
        return {
            restrict : 'E',
            templateUrl : 'footer.html'
        };
    });

    app.controller('menuController', function($scope, $location, rememberService){
        $scope.isActive = function(route){
            return rememberService.getActualPage() === route;
        };
    });
    app.controller('MainController', function(Page){
        this.page = pages;
    });

    app.factory('rememberService', function($location) {
        return {
            getActualPage: function(){
                var arr = $location.$$absUrl.split("/");
                var pageName = arr[arr.length -1];
                return pageName;
            }
        };
    });
    app.factory('Page', function(rememberService) {
        return {
            getTitle: function(){
                return "neo4Art - "+ pages[rememberService.getActualPage()];
            }
        };
    });

})();

To handle footer and header with Directives (< header>< /header>)

this is (part of) the code used to create the svg. I will only show you what I am interested in, the part that read the "on-field" measurements.

function Search(){
    var width = $(".container-svg").width();
    var height = $(".container-svg").height();
    console.log("width:" + width + " - height:"+ height);   
}

Before the use of angular I was using this in:

$(window).load(function(d) {
    var search = new Search();
});

and all was going pretty well.

now using:

angular.element(window).load(function() {
    var search = new Search();
});

I have a wrong height inside the var. It seems like the "new Search()" is called when the svg is still too high (the header is not yet rendered)

This is the html of the index (simplified)

<!DOCTYPE html>
<html lang="it-IT" ng-app="neo4art" ng-controller="MainController as mc">
<head>
<meta charset="utf-8">
<script src="resources/js/jquery/jquery-2.1.3.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<link rel="stylesheet" type="text/css" media="screen" href="resources/css/style.css" />
<link rel="stylesheet" type="text/css" media="screen" href="resources/css/style-index-new.css" />
<link rel="stylesheet" type="text/css" href="resources/css/font-awesome-4.3.0/css/font-awesome.min.css" />
<title>{{"neo4Art - " + mc.page["about.html"]}}</title>
</head>
<body>
    <script type="text/javascript" src="resources/js/angular.min.js"></script>
    <script type="text/javascript" src="resources/js/search.js"></script>
    <script type="text/javascript" src="resources/js/neo4art.js"></script>
    <div class="container-page scrollbar-macosx" when-ready="isReady()">
        <div class="content-home">
            <header></header>
            <div class="text-home">
                <svg class="container-svg">
            </svg>
            </div>
            <div class="footer">
                &copy; 2015 neo4<span class="palette-dark-blue">A</span><span class="palette-blue">r</span><span class="palette-orange">t</span> - All
                rights reserved &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="//www.iubenda.com/privacy-policy/430975" class="iubenda-white iubenda-embed"
                    title="Privacy Policy">Privacy Policy</a>
                </div>
        </div>
    </div>
</body>
</html>

This is the code of the header:

<div class="header">
                <div class="logo">
                    <a href="index.html"><img src="resources/img/neo4art-logo-big.png" /></a>
                    <div class="motto">Traversing Art through its connections</div>
                </div>
                <form method="get" action="graph.html" name="query">
                    <div class="menu">
                        <div class="search-bar-container">
                            <span class="icon"><i class="fa fa-search"></i></span><input type="search" id="search" placeholder="Search..." name="query" />
                        </div>
                        <ul>
                            <li><a href="javascript:void(0)" class="current">HOME</a></li>
                            <li><a href="about.html">ABOUT</a></li>
                            <li><a href="genesis.html">GENESIS</a></li>
                            <li><a href="team.html">TEAM</a></li>
                        </ul>
                    </div>
                </form>
            </div>

Without angularjs it is rendered correct, with angular I have a wrong value like the image is not loaded at all.

I hope my question is clear enough, the problem I think is in when each function is called during the load of the page.

EDIT: It's strange also that sometimes the page is loaded correctly (random occurency)

AngularJS version 1.3.16

Gianmarco
  • 2,536
  • 25
  • 57
  • What version of angular are you using? I'm only asking this because I switched to 1.4.3 this morning and was having the same problem with charts – Razvan B. Jul 17 '15 at 15:03
  • my version is AngularJS v1.3.16 – Gianmarco Jul 17 '15 at 15:13
  • I know this can be complex, but if you can provide a plunker that reproduce the issue we could make further investigations. – Okazari Jul 17 '15 at 15:20
  • can't use pageload for this, put the function in a directive so the element exists when it is called – charlietfl Jul 17 '15 at 15:34
  • a snippet of the code is complex to create, it needs many files. charlietfl can you explain better what you said about the directives? – Gianmarco Jul 17 '15 at 15:44
  • @Gianmarco The angular page lifecycle is pretty complex too, unfortunately. I think we probably need to see everything that defines the rendering pipeline of the header and the container-svn element, if not the rest of the page. – Ethan Jewett Jul 17 '15 at 17:12
  • github.com/GianmarcoL/neo4art will this do? main folder is neo4art-webapp/src/main/webapp/ the page is index.html and that's all the code – Gianmarco Jul 17 '15 at 17:48
  • Once you started using Angular.js, you should do every dom manipulations in Angular.js. I think you should put svg drawing logic into a directive. In directive you should get dimensions and do drawing inside `$timeout(fn, 0)` to make sure it is properly appended to page. But I'm still not sure if this is going to work. Also, AFAIK there is no (at least non-hacky) way to detect Angular.js finished "loading". – Umut Benzer Jul 22 '15 at 11:48
  • 1
    why don't you try to create a something-like-almost-working answer? the project is open source so the code is all there in github – Gianmarco Jul 22 '15 at 13:18
  • @Gianmarco first thought: does jquery load in first place (before angular) every time? From the docs: `If jQuery is available, angular.element is an alias for the jQuery function. If jQuery is not available, angular.element delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."`. I would try to move all your scripts from `head` to the end of the `body` tag, assuring jQuery to be the first one. – jarandaf Jul 27 '15 at 19:15
  • Is this dependant from the order of the script Tag in the html? – Gianmarco Jul 27 '15 at 19:18

2 Answers2

2

So you are having this weird cross road in understanding of angular. First lets talk about angular.element is not the same as a jquery element. You shouldn't be doing DOM manipulation from an element you create like that you should have a directive with a link function to make sure this is happening in the digest cycle when you want it to. This is a hard concept to get but I think the best example I can find is from this other question.

Angular.js: set element height on page load

This does a reasonable job of showing and explaining what we are talking about.

Community
  • 1
  • 1
James
  • 1,514
  • 12
  • 30
  • I agree with you on the not doing dom manipulation, but the angular documentation reads: "If jQuery is available, angular.element is an alias for the jQuery function.". So in this case I'd say angular.element is the same as jQuery. – Simon Groenewolt Jul 27 '15 at 16:46
  • I am rewarding this answer the bounty, even if I am not going to accept it, I found some useful stuff, but not yet the answer. I will be able to focus on this argument in a week, due to my vacation ( :D ). I am thinking about start a new bounty in the future – Gianmarco Jul 28 '15 at 06:55
  • Thanks for the bounty glad I could be of some help. – James Jul 28 '15 at 17:23
0

A simple trick to see if it's related to initialization of the page would be to wrap you measuring code in a setTimeout call and delay it for 500ms. If this fixes the measurement you'd have to go a search for the actual correct place to put your measuring code :-)

Simon Groenewolt
  • 10,607
  • 1
  • 36
  • 64