I'm creating an ecommerce site that has infinite scroll in the catalog page. I want to know how many times each product is show to an user in the screen (impressions). The problem is how to get the new 12 elements that renders every time a user scrolls down to a new page. Than pass their ids to the server and stores their impressions. Is there a way to access the new elements? I checked laravel documentation and I saw nothing about this.
This is my code that renders the products array in the template:
<div class="product-one">
#foreach($products as $product)
<div class="col-md-3 product-left">
<div class="p-one simpleCart_shelfItem">
<a href="{{ route('getprodpage', ['id' => $product->id]) }}">
<img src="{{ $product->image_url1}}" alt="" />
<div class="mask">
<span>Comprar</span>
</div>
</a>
<h4>{{ $product->name }}</h4>
<p><a class="item_add" href="#"><i></i>
<span class=" item_price">
R$ {{$product->price_min}}
</span></a>
</p>
</div>
</div>
#endforeach()
<div class="clearfix"> </div>
</div>
<?php echo $products->render(); ?>
And this is the infinite scroll javascript:
$(function() {
$('.shoes').jscroll({
loadingHtml: '<center><img src="{{ URL::asset('images/loading.gif') }}" alt="Loading" /> </center>',
autoTrigger: true,
padding: 0,
nextSelector: '.pagination li.active + li a',
contentSelector: 'div.shoes',
callback: function() {
$('ul.pagination:visible:first').hide();
}
});
});
I believe this question has been asked and answered already.
jQuery: How can I trigger an event when a div comes into view?
This post has an answer to see if an element is in the view port and also another answer for an event for when elements are in the view port.
Related
I have a HTML div like this,
<div class="coment-area ">
<ul class="we-comet">
{% for j in comment %}
<div id="delete_comment{{j.id}}" class="mt-3">
{% if j.post_id.id == i.id %}
<li >
<div class="comet-avatar">
{% if j.user_id.User_Image %}
<img class="card-img-top" style=" vertical-align: middle;width: 50px;height: 50px;border-radius: 50%;" src= {{ j.user_id.User_Image.url }} alt="">
{% else %}
<img class="card-img-top" style=" vertical-align: middle;width: 60px;height: 60px;border-radius: 50%;" src="static\images\resources\no-profile.jpg">
{% endif %}
</div>
Inside of it is a For Loop that is executed when the page is first loaded.
Below this For Loop is a Comments Button
<div >
<button type="submit" onclick="comment_save(event,{{i.id}})" class= "my-2 ml-2 px-2 py-1 btn-info active hover:bg-gray-400 rounded ">Comment</button>
</div>
</div>
</li>
</ul>
</div>
Whenever this button of Comments is clicked, a function in Javascript is called which is defined below,
function comment_save(event,post_id)
{
var comment_value=$("#comment_value"+post_id).val();
var user_id=$("#comment_user_id"+post_id).val()
postdata={
"comment_value":comment_value,
"user_id":user_id,
"post_id":post_id
}
SendDataToServer("readmore",postdata,function()
{
alert()
})
$("#comment_value"+post_id).val(" ")
<! --- document.location.reload().. Something here that refresh that for loop --->
}
What I want is this that whenever the button is clicked, it re-executes that for Loop inside my main div without having to refresh the page. I have been trying to do this for two days but could not find any solution to this. Can anyone help me in doing this?
The Django Templating Language is executed server-side. That means the client (browser, running Javascript) has no access to it whatsoever.
Some of your options are:
Do everything back-end: Re-render the template (which you said don't want to do).
Do everything front-end: You could have your view function return the data used in your template loop and re-implement it in your front-end (but that makes the original template loop kind of pointless).
Hybrid: Return the data for only the new comment in your response and add it to the list with Javascript.
I'm currently trying to figure out how to use templates in angular. At present, I'm playing with ui.router (angular-ui-router) but I can't find good documentation on how the templating language is used to embed a sub-template view, especially as relates to a repeating element for different model instances.
BACKGROUND:
I am basically converting a static-local-filesystem image uploader/manager to work with amazon S3. The background essentials are already worked out, now I'm trying to improve the UI itself by converting it from 10 year old javascript to angular.js. I have it 'working' for an all-in-one html page but would prefer to modularize it to make it more dynamic.
CONTEXT:
I get a list of objects under a given prefix back from a listObjectsV2() call to the AWS sdk via the s3 client. I parse the results to break it into a pseudo-directory tree then display one directory at a time starting at the [virtual] root dir just after the prefix. (FYI the prefix is a userid)
I built a UserDir object that uses a PseudoDir sub object to define a virtual directory with array properties for 'subdirs' (more PseudoDir objects representing virtual sub-directories) and 'images' (S3 objects that are image files of one type or another).
What I want to display for any given 'current' directory (e.g. "" or the user root) is first a list of folder icons for each the curDir.subdirs, then a thumbnail icon for each of the curDir.images.
QUESTION:
I already have this working from a single html file and even managed to figured out how to use ui.router to create a for the main page. Now I want to modularize it so that a different controller will handle folder icon/info behavior, and another for image icons/behaviors.
i.e. I have already started building a 'FolderController' and a 'ImageController' and would like the ngRepeat for 'image in curDir.images' for example, to invoke a state with it's own template but I can't seem to find an example on how to do that.
Here is the current all-in-one template code. But I would like to move each sub-block into a state for FolderController with a templates/folder.html template and one for ImageController with a templates/image.html but can't seem to find an example of how to write the syntax:
<!-- folders -->
<div ng-repeat="(folder, pDir) in subdirs" ng-controller="FolderController" ng-init="folderName=folder;awsObject=pDir">
<div id="{{folderName}}" class="Item">
<div class="Icon ui-draggable ui-draggable-handle">
<img id="{{folderName}}Icon" src="../../images/folder.png">
</div>
<div id="{{folderName}}Desc" class="Description">
<span id="{{folderName}}Name" class="filename" title="{{folderName}}/">{{folderName}}/</span>
</div>
</div>
</div>
<!-- images -->
<div ng-repeat="(filename, uImage) in images" ng-controller="ImageController" ng-init="uImage=uImage">
<div id="image{{uImage.hash}}" class="Item">
<div class="Icon ui-draggable ui-draggable-handle">
<img id="icon{{uImage.hash}}" ng-src="{{ uImage.thumbSrc }}"></div>
<div id="desc{{uImage.hash}}" class="Description">
<span id="name{{uImage.hash}}" class="filename" title="{{filename}}">{{filename}}</span>
<img id="thumb{{uImage.hash}}" src="../../images/tick_image-services.png" class="Check Right" ng-show="uImage.usedInLayout" title="Used in layout"><br />
<span id="date{{uImage.hash}}" ng-show="(uImage.mtime > 0)">Date uploaded: {{ uImage.mtime | date: 'EEE MMM dd yyyy' }}</span><br />
<span id="size{{uImage.hash}}" ng-show="(uImage.size > 0)">Size: {{ uImage.size | humanizeBytes }}</span><br />
<span id="dims{{uImage.hash}}" ng-show="((uImage.width > 0) && (uImage.height > 0))">Dimensions: {{ uImage.width }} x {{ uImage.height }} pixels</span><br />
<span id="aspect{{uImage.hash}}" ng-show="(uImage.aspectRatio)">Aspect Ratio: <span class="AspectRatio">{{ uImage.aspectRatio }}</span></span><br />
</div>
</div>
</div>
You can create two components, one for folders and one for images, see here for official docs.
A rough draft would look like:
angular.module('myApp').component('images', {
templateUrl: 'imageList.html',
bindings: {
images: '='
}
});
imageList.html:
<div ng-repeat="(filename, uImage) in images" ng-controller="ImageController" ng-init="uImage=uImage">
<div id="image{{uImage.hash}}" class="Item">
<div class="Icon ui-draggable ui-draggable-handle">
<img id="icon{{uImage.hash}}" ng-src="{{ uImage.thumbSrc }}"></div>
<div id="desc{{uImage.hash}}" class="Description">
<span id="name{{uImage.hash}}" class="filename" title="{{filename}}">{{filename}}</span>
<img id="thumb{{uImage.hash}}" src="../../images/tick_image-services.png" class="Check Right" ng-show="uImage.usedInLayout" title="Used in layout"><br />
<span id="date{{uImage.hash}}" ng-show="(uImage.mtime > 0)">Date uploaded: {{ uImage.mtime | date: 'EEE MMM dd yyyy' }}</span><br />
<span id="size{{uImage.hash}}" ng-show="(uImage.size > 0)">Size: {{ uImage.size | humanizeBytes }}</span><br />
<span id="dims{{uImage.hash}}" ng-show="((uImage.width > 0) && (uImage.height > 0))">Dimensions: {{ uImage.width }} x {{ uImage.height }} pixels</span><br />
<span id="aspect{{uImage.hash}}" ng-show="(uImage.aspectRatio)">Aspect Ratio: <span class="AspectRatio">{{ uImage.aspectRatio }}</span></span><br />
</div>
</div>
and your original html would look like:
<!-- folders -->
<div ng-repeat="(folder, pDir) in subdirs" ng-controller="FolderController" ng-init="folderName=folder;awsObject=pDir">
<div id="{{folderName}}" class="Item">
<div class="Icon ui-draggable ui-draggable-handle">
<img id="{{folderName}}Icon" src="../../images/folder.png">
</div>
<div id="{{folderName}}Desc" class="Description">
<span id="{{folderName}}Name" class="filename" title="{{folderName}}/">{{folderName}}/</span>
</div>
</div>
</div>
<image-list [images]="images" ></image-list>
EDIT
Here is an example plunker which shows a simple implementation of a component, with data binding and ng-repeat in it, no need for ui-router for what you asked for. Please note that the html I wrote above is a botched copy paste of what you wrote - so the double ng-repeat was a mistake, updated the html.
I have a product page where products from database is showing. Code for that product page.
<!-- language: lang-html -->
<div class="tab-content vertical col-md-10 col-lg-10 col-sm-9 col-xs-9 left-aligned">
<div class="tab-pane fade in active">
<perfect-scrollbar wheel-propagation="true" suppress-scroll-x="true" min-scrollbar-length="8" class='ps-scrollbar'>
<div class="ecommerce_product col-lg-3 col-md-4 col-sm-4 col-xs-6" ng-repeat="products in data | filter:search | startSearchFrom:(currentPage-1)*entryLimit | limitTo:entryLimit">
<div class="thumb">
<img class="img-responsive" ng-src="../upload/{{products.image}}">
<div class="overlay"><a ng-href="#/app/ecommerce/product-edit?id={{products.id}}" data-ng-click="editUser(products)" ><i class="material-icons">shopping_cart</i></a></div>
</div>
<div class="product-info">
<h4><a ui-sref="app.mus-song-view"><b>{{ products.pname | limitTo: 8 }}{{products.pname > 8 ? '...' : ''}}</b></a></h4>
<p class="price"> <b>Price:</b> {{products.price}}</p>
<p class="price"><b>Sale Price:</b>{{products.price - products.discount | number:2}}</p>
</div>
</div>
</perfect-scrollbar>
</div>
</div>
<!-- end snippet -->
Now the problem is i want to edit a particular product in a different page when clicked on the product. I passed the id in the url. But i am not being able to call the url parameter from the controller and at the same time pass the parameter to a php file so that i can call the data from the database.
Is there anyone who can help me from this. Please.
To get a url param you can use: $routeParams
For example you can get the id of a product from that route:
www.yoursite.com/product/id
by doing:
var id = $routeParams.id
In you HTML/PHP page after you pass param to the URL
Suppose your URL will be example.com/edit?id=1
and in the page when you visit above URL.
<?php
$id = $_GET['id'];
?>
<div ng-controller="my_ctrl">
<input type="hidden" ng-model="myID" value="<?php echo $id; ?>" />
{{myID}}
</div>
Now in your angular controller my_ctrl you can access your value (id) by using
myID
In your controller (my_ctrl):
//.............
$scope.myID = ""; //Initial Value
//.............
Remember Angular is both way data binding framework, so if you change the value of a model in you HTML will reflect on JS and if you change value in JS will reflect on View.
I am pretty close to having this app finished, but have one last hurdle. I am dynamically populating tabs and data via the WordPress Rest API and when I only had 2 tabs it worked wonderfully, but when I added tab 3 and 4 I ran into issues. When I click tabs 2-4 all tabs receive the "active" class instead of just the one that was clicked; thus also all 3 tabs content data also displays.
Here is the code:
var homeApp = angular.module('homeCharacters', ['ngSanitize']);
homeApp.controller('characters', function($scope, $http) {
$scope.myData = {
tab: 0
}; //set default tab
$http.get("http://bigbluecomics.dev/wp-json/posts?type=character").then(function(response) {
$scope.myData.data = response.data;
});
});
homeApp.filter('stripTags', function() {
return function(text) {
return text ? String(text).replace(/<[^>]+>/gm, '') : '';
};
});
<section class="characters" ng-app="homeCharacters" ng-controller="characters as myData">
<div class="char_copy">
<h3>Meet the Characters</h3>
<div class="char_inject" ng-repeat="item in myData.data" ng-show="myData.tab === item.menu_order">
<div class="copy_wrap">
<h3>{{ item.acf.team }}:</h3>
<h2>{{ item.acf.characters_name }} <span>[{{item.acf.real_name}}]</span></h2>
<p class="hero_type">{{ item.acf.hero_type }}</p>
<div class="description" ng-repeat="field in item.acf.character_description">
<p>{{field.description_paragraph}}</p>
</div>
Learn More
</div>
<div class="image_wrap">
<img src="{{ item.acf.homepage_full_image.url }}" />
</div>
</div>
</div>
<div class="char_tabs">
<nav>
<ul ng-init="ch.tab = 0">
<li class="tab" ng-repeat="item in myData.data" ng-class="{'active' : item.menu_order == myData.tab}">
<a href ng-click="myData.tab = item.menu_order">
<img src="{{ item.featured_image.source }}" />
<div class="tab_title_wrap">
<h3>{{ item.acf.characters_name }}</h3>
</div>
</a>
</li>
</ul>
</nav>
</div>
</section>
I would love any ideas! Thanks!
The code seems to work, see Fiddle. What are the values of menu_order? If they are the same for cases 2-4, then that would explain the behaviour.
I'm using jScroll (jscroll.com) in my Laravel 5.1 application for infinite scrolling. I'm further using some jquery which I want to be triggered on clicking the 'Like' button for each post. Jquery is working perfectly on the first page's posts i.e localhost/myproject/index but it is not triggered for the posts which are appended by jScroll from the next page(s) i.e localhost/myproject/index?page=2 etc.
Here is my code for displaying the posts:
#foreach($posts as $post)
<div class="panel panel-default">
<div class="panel-body post">
<h3>{{ $post->title }}</h3>
<hr>
<p>{{ $post->discripion }}</p>
</div>
<div class="panel-footer">
<div class="btn-group">
<button type="button" data-id="{{$post->id}}" class="btn btn-default like-btn">Like</button>
</div>
</div>
</div>
#endforeach
and the simple jquery that I want to be triggered for each posts is:
<script type="text/javascript">
$('button.like-btn').on('click',function(){
var post_id = $(this).data('id');
alert('Liked post with id = ' + post_id);
});
</script>
It's because jquery doesn't bind to those elements (they are not in the DOM initially). Bind it to document instead, like this:
$(document).on("click", 'button.like-btn', function(event) {
alert("new link clicked!");
});
Look here for a little more