Frederico Jesus
Frederico Jesus

Reputation: 668

What's the best way to append an element using angular?

My objective is to show a grid of products and ads between them.

warehouse.query({limit: limit, skip: skip}).$promise
    .then(function(data) {
        for (var i = 0; i < data.length; i++) {
            var auxDate = new Date(data[i].date);
            data[i].date = auxDate.toISOString();
        }

        Array.prototype.push.apply($scope.products, data);

        //add an img ad        
        var warehouseElem = angular.element(document.getElementsByClassName('warehouse')[0]);
        var newAd = $sce.trustAsHtml('<img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>');
        warehouseElem.append(newAd);

        skip += 9
    });

Doesn't work. I already tried simply using pure javascript like,

var warehouseElem = document.getElementsByClassName('warehouse')[0];
var newAd = document.createElement('img');
warehouseElem.appendChild(newAd);

Also doesn't work. I suppose I need to do something with angular, can't find out what. I think it's sanitize but maybe I just don't know how to use it. Remember I need to inject an img every once in a while between products.

Upvotes: 1

Views: 334

Answers (3)

Walfrat
Walfrat

Reputation: 5353

This is a job for ng-repeat!

<div ng-repeat="data in datas">
    <div>[show data here]</div>
    <img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>
</div>

If you have bind your "datas" in scope and Math too like this in your controller like this it should works

$scope.datas // this is your list of products
$scope.Math = Math;

If you don't want to spam add for each line you can use ng-if with $index like this :

<div ng-if="$index%2==0">
    <img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>
</div>

This will make it display add every 2 lines.

Since you seemed to come from a jQuery-like (or native DOM manipulation) background, I suggest you to read that post : "Thinking in AngularJS" if I have a jQuery background?.

This will explain you why in angular you almost don't manipulate DOM and quite some other things (only in directives).

EDIT : to fix the grid problem, just merging my two html block build your array of datas like this : $scope.myArray = [product[0], ad[0] or just an empty string it will work still, product[1], ad[1]] And the html

<div ng-repeat="data in datas">
    <div ng-if="$index%2==0">[show data here]</div>
    <img ng-if="$index%2==1 src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>
</div>

Upvotes: 2

tebereth
tebereth

Reputation: 189

In AngularJS you should generally avoid doing DOM manipulation directly and rather rely on angular directives like ng-show/ng-hide and ng-if to dynamically hide sections of a template according to the specific case.

Now back to the problem at hand.

Assuming that you are trying to render a list of products loaded with the code displayed above and display an ad for some of them, you can try the following.

<!-- place the img element in your template instead of appending -->
<div ng-repeat="product in products">
    <!-- complex product template-->
    <!-- use ng-if to control which products should have an ad -->
    <img ng-src="product.adUrl" ng-if="product.adUrl" />
</div>

Then in your controller set adUrl for products that should have an ad displayed.

warehouse.query({limit: limit, skip: skip}).$promise
.then(function(data) {
    for (var i = 0; i < data.length; i++) {
        var hasAd = // set to true if this product should have an add or not
        var auxDate = new Date(data[i].date);
        data[i].date = auxDate.toISOString();
        if(hasAd){
            data.adUrl = "/ad/?r=" + Math.floor(Math.random()*1000);
        }
    }

    Array.prototype.push.apply($scope.products, data);

    skip += 9
});

I am most probably assuming too much. If that is the case please provide more details for your specific case.

Upvotes: 1

kensplanet
kensplanet

Reputation: 494

If you declare a scope variable,

$scope.newAd = $sce.trustAsHtml('<img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>');

and in your HTML template, have a binding like

<div ng-bind-html="newAd"></div>,

it should work.

Upvotes: 0

Related Questions