1

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.

Frederico Jesus
  • 649
  • 6
  • 14
  • DOM manipulation in an angular controller is a really bad practice. The pure angular approach to your problem would likely include using ng-repeat and possibly a custom directive. – jbrown Jan 18 '16 at 22:03
  • but how can I add it in the middle of the products grid just when I want ?? – Frederico Jesus Jan 18 '16 at 22:10

3 Answers3

2

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>
Community
  • 1
  • 1
Walfrat
  • 5,363
  • 1
  • 16
  • 35
  • it worked almost perfectly, but I still have a problem. Sometimes when the product which will also have an ad is the last in a row he will collapse because there is no space in view and the result is a grid space with no product and no ad. I'm using display flex and flex-wrap wrap, thinking in how to solve it but dunno yet. If you want to help I can share my code. – Frederico Jesus Jan 18 '16 at 22:54
  • look http://imgur.com/BsDijbA , this is my problem with that solution, that's why I wanted everything separated, I think this is impossible to solve, or it would take some javascript code to correct it. – Frederico Jesus Jan 18 '16 at 23:16
  • 1
    it's pretty easy in fact, i edited my answer :). If you need something more complex build an array of object like {type;'product', data:}/{type:'ad', data: – Walfrat Jan 18 '16 at 23:35
  • nice dude thanks, I still had to do a trick because I was skipping one product, so what I did was when I displayed the ad I came back one iteration (i--). Btw I used both your solution and @tebereth solution, thank you both for the help!! – Frederico Jesus Jan 19 '16 at 00:07
1

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.

tebereth
  • 73
  • 1
  • 6
  • this would work, and it's almost nearly the solution I'm using. The problem is this http://imgur.com/BsDijbA , they collapse when it happens to stay in the last spot of the row. That's why I wanted to keep everything separated – Frederico Jesus Jan 18 '16 at 23:27
0

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.

kensplanet
  • 493
  • 8
  • 15
  • but how can I add it in the middle of the products grid just when I want ?? – Frederico Jesus Jan 18 '16 at 22:11
  • You can split the products array into two parts. Product1 array contains products before the Ad and Product2 array after the ad. In my template, I'll iterate over Product1, then display Ad, and then iterate over Product2. – kensplanet Jan 18 '16 at 22:13