Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am experimenting with AngularJS's UI-Router for nested views, which seems to be working. However, in line 97, you will find a resolve, which delays the initialization of the nested view until the data is received and processed.

You will notice that I am capturing the json feed into localStorage (line 123). I am using this to save a copy of each post for fast data retrieval and UI binding instead of having to wait for a second Ajax request to retrieve that data.

The Problem

If you click, any of the links returning from the ajax request, a nested view will appear. The data filling out of the view seems to have been converted to text, entirely. No HTML tag renders as HTML... one complete string.

Diagnosis

I am not sure what is causing this. Could it be because I used jQuery Ajax call to retrieve that information?

I previously tried to use Angular's own $http.jsonp but I kept getting a type error that I just could NOT figure out... so maybe angular is good at only data "it" fetches?? I personally would like to ditch jQuery in this little app, but it seems to be the only option is is retrieving the data for me without problems.

Request

Would like to have the data binded to the final nested view to render as HTML, and not as a string. Thanks! jsFiddle: http://jsfiddle.net/halkibsi/Z5aEs/11/

Note

This app 3rd level nested view does not show in Firefox, only worked in Chrome and Safari browsers. Did not test in IE or Opera.

    // LOAD MODULES
    angular.module('myApp', ['ui.router'])
.run([ '$rootScope', '$state', '$stateParams', function ($rootScope, $state, $stateParams) {
    $rootScope.$state = $state;
    $rootScope.$stateParams = $stateParams;
  }]);


    /*************************/
    // STATES
    /*************************/
    angular.module('myApp')
    .config( ['$stateProvider', '$urlRouterProvider', function ( $stateProvider, $urlRouterProvider ) {

    /***************************/
    // Redirects and Otherwise //
    $urlRouterProvider
        .when('/en', '/en/news')
        .otherwise('/');


    /************************/
    // State Configurations //
    $stateProvider

        /********/
        // HOME //
        /********/
        .state('home', {
            url: '/',
            template: 
                '<div>'+
                '<header class="section-title"><h1>HOME</h1></header>'+
                '<ul class="nav">'+
                '<li ng-class="{ active: $state.includes(\'arabic\') }"><a ui-sref="arabic">عربي</a></li>'+
                '<li ng-class="{ active: $state.includes(\'english\') }"><a ui-sref="english">English</a></li>'+
                '</ul>'+
                '</div>',
        })

        /**********/
        // ARABIC //
        /**********/
        .state('arabic', {
            url: '/ar',
            //abstract: true,
            template:
                '<div dir="rtl">'+
                    '<header class="section-title"><h1>الواجهة العربية</h1></header>'+
                    '<ul class="nav">'+
                        '<li ng-class="{ active: $state.includes(\'home\') }"><a ui-sref="home">الصفحة الرئيسية</a></li>'+
                        '<li ng-class="{ active: $state.includes(\'english\') }"><a ui-sref="english">English Interface</a></li>'+
                        '<li><a href="#/ar/ndc-news">أخبار</a></li>'+
                        '<li><a href="#/ar/ndc-photos">صور</a></li>'+
                        '<li><a href="#/ar/ndc-videos">فيديو</a></li>'+
                        '<li><a href="#/ar/ndc-podcasts">صوتيات</a></li>'+
                    '</ul>'+
                    '<!-- MAIN UI VIEW FOR THIS TEMPLATE -->'+
                    '<div ui-view ng-animate="{enter:\'fade-enter\'}"></div>'+
                '</div>',
        })

        /***********/
        // ENGLISH //
        /***********/
        .state('english', {
            //abstract: true,
            url: '/en',
            template:
                '<div>'+
                    '<header class="section-title"><h1>English Interface</h1></header>'+
                    '<ul class="nav">'+
                        '<li ng-class="{ active: $state.includes(\'home\') }"><a ui-sref="home">Home</a></li>'+
                        '<li ng-class="{ active: $state.includes(\'arabic\') }"><a ui-sref="arabic">الواجهة العربية</a></li>'+
                        '<li ng-class="{ active: $state.includes(\'english.news\') }"><a ui-sref="english.news">News</a></li>'+
                        '<li ng-class="{ active: $state.includes(\'english.photos\') }"><a ui-sref="english.photos">Photos</a></li>'+
                        '<li ng-class="{ active: $state.includes(\'english.videos\') }"><a ui-sref="english.videos">Videos</a></li>'+
                        '<li ng-class="{ active: $state.includes(\'english.podcasts\') }"><a ui-sref="english.podcasts">Podcasts</a></li>'+
                    '</ul>'+
                    '<!-- MAIN UI VIEW FOR THIS TEMPLATE -->'+
                    '<div ui-view ng-animate="{enter:\'fade-enter\'}"></div>'+
                '</div>',
        })

            // English -> NDC News
            .state('english.news', {
                url: '/news',
                template:
                    '<header class="section-title"><h2>News</h2></header>'+
                    '<ul>'+
                      '<li ng-repeat="post in posts"><a ui-sref="english.news.single({postId:post.id})">{{ post.title }}</a></li>'+
                    '</ul>'+
                        '<div style="margin: 0 0 0 2em;">'+
                        '<!-- MAIN UI VIEW FOR THIS TEMPLATE -->'+
                        '<div class="ui-view-lev2" ui-view></div>'+
                    '</div>',
                resolve: {
                    news: function() {
                            return $.ajax({
                                type: "GET",
                                url: "http://ndcye.org/api/get_posts/?post_type=post&cat=3&callback=?",
                                dataType: "jsonp",
                                success: function(response){
                                    //console.log(response);

                                    var newsList = [];
                                    for ( var i=0; i < response.posts.length; i++) {

                                        var id = response.posts[i].id;
                                        var title = response.posts[i].title;
                                        var thumbnail = response.posts[i].thumbnail_images.mobile.url;
                                        var excerpt = response.posts[i].excerpt;
                                        var content = response.posts[i].content;

                                        // SAVE POST AS AN OBJECT
                                        var post_object = {
                                            id: id,
                                            title: title,
                                            thumbnail: thumbnail,
                                            excerpt: excerpt,
                                            content: content,
                                        };
                                        if (localStorage.getItem( 'post_object_'+id ) === null) {
                                            localStorage.setItem( 'post_object_'+id, angular.toJson(post_object) );
                                        }

                                        newsList.push(post_object);
                                    }

                                    localStorage.setItem( 'ndc_news', angular.toJson(newsList) );
                                    console.log( newsList );
                                },
                                error: function(){
                                    console.log("error!");
                                }
                            });
                    }
                },
                controller: ['news', '$scope', '$state', function (news, $scope, $state) {
                    $scope.posts = news.posts;
                    console.log($scope.posts);
                }], // controller end
            })

                // English -> NDC News Single
                .state('english.news.single', {
                    url: '/{postId:[0-9]{1,4}}',
                    template:
                        '<header class="section-title"><h3>{{ singlePost.title }}</h3></header>'+
                        '<div>{{ singlePost.content }}</div>',
                    controller: ['$scope', '$state', '$stateParams', function ($scope, $state, $stateParams) {
                        var singlePost = '';
                        singlePost = angular.fromJson( localStorage.getItem( 'post_object_' + $stateParams.postId ) );

                        $scope.singlePost = singlePost;
                        console.log( singlePost );
                    }]
                })








            // English -> NDC Photos
            .state('english.photos', {
                url: '/photos',
                template:
                    '<header class="section-title"><h2>Photos</h2></header>'+
                    'Photo albums go here',
            })

            // English -> NDC Videos
            .state('english.videos', {
                url: '/videos',
                template:
                    '<header class="section-title"><h2>Videos</h2></header>'+
                    'YouTube playlists go here',
            })

            // English -> NDC Podcasts
            .state('english.podcasts', {
                url: '/podcasts',
                template:
                    '<header class="section-title"><h2>Podcasts</h2></header>'+
                    'Podcast playlists go here',
            })



  } // end function ($stateProvider,   $urlRouterProvider)

    ]) // end .CONFIG
    ; // ens STATES
share|improve this question
1  
demo works for me in jsfiddle. Might consider using a service to store your data and handle storage conversions. storage logic doesn't make sense to me –  charlietfl Nov 17 '13 at 17:24
    
You are absolutely correct, my apologies for not explaining the logic behind using localStorage in this case. I intended to use factory services to create and update localStorage value of ajax results. However, I got stuck with this problem, and thus did not completely integrate localStorage in a way that would of made sense to you... but that was not what I was having trouble with. Thanks :) –  halkibsi Nov 17 '13 at 18:05
    
+1 because this question is well written and very clear. –  Utopik Nov 17 '13 at 19:35
add comment

1 Answer

up vote 1 down vote accepted

There were two problems with the program:

  1. You were using {{ ... }} to bind singlePost.content to HTML. This necessarily escapes the HTML
  2. Merely using ng-bind-html="singlePost.content" will not work because angular now only renders trusted HTML.

The only changes needed were in the state english.news.single:

.state('english.news.single', {
  url: '/{postId:[0-9]{1,4}}',
  template:
          '<header class="section-title"><h3>{{ singlePost.title }}</h3></header>'+
          '<div ng-bind-html="content"></div>',
  controller: ['$scope', '$state', '$stateParams', '$sce', function ($scope, $state, $stateParams, $sce) {
          var singlePost = '';
          singlePost = angular.fromJson( localStorage.getItem( 'post_object_' + $stateParams.postId ) );

          $scope.singlePost = singlePost;
          $scope.content = $sce.trustAsHtml(singlePost.content);
          console.log( singlePost );
  }]
})

Working example: http://jsfiddle.net/Z5aEs/12/

Side note: It works for me in Firefox 25 as well.

share|improve this answer
    
musically_ut... your solution was simply perfect, thanks!. I guess there is a lot more of AngularJS that I need to get a grasp on. BTW, you are correct that it works in FF25 in jsFiddle, but not on my local XAMPP server... weird. –  halkibsi Nov 17 '13 at 17:59
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.