I am trying to create a crawler for a project and I'm running my head up against the wall with this problem. I am trying to use CasperJS to click on the buttons on a page and return the URL that the page gets navigated to.
<product-searcher-results>
<div flex="33" flex-sm="50" flex-xs="50" layout="row" ng-repeat="product in resultsCtrl.products" class="layout-row flex-xs-50 flex-sm-50 flex-33" style="">
<md-card flex="" ng-click="resultsCtrl.goToDetail( product )" ng-class="{ 'md-whiteframe-3dp': hover }" ng-mouseenter="hover = true" ng-mouseleave="hover = false" class="fp-card fp-card-product-result mobile-padding _md flex" role="button" tabindex="0">
<img static-src="https://products.freedompop.com/kyo-c6725bk/kyo-c6725bk_C10.jpg" alt="Cheap Kyocera Hydro Vibe, 8GB Black (CDMA)" class="md-card-image" style="padding-top:10px" src="https://products.freedompop.com/kyo-c6725bk/kyo-c6725bk_C10.jpg">
<div layout="row" layout-align="end center" ng-init="condition = resultsCtrl.getCondition( product )" class="label-row layout-align-end-center layout-row">
<div ng-show="condition.isVisible" ng-class="{ grey: condition.labelColor, tiny: resultsCtrl.$mdMedia( 'xs' ) }" class="ui label ng-hide grey" aria-hidden="true">New</div>
</div>
<md-card-title>
<md-card-title-text>
<span class="md-title">Kyocera Hydro Vibe, 8GB Black (CDMA)</span>
</md-card-title-text>
</md-card-title>
<md-card-content>
<div layout="row" layout-align="end end" class="price-sizing layout-align-end-end layout-row">
<div class="msrp results-msrp">
<span class="value price-strikethrough">
$249.99
</span>
</div>
<!----><div ng-if="product.products[0].retailPrice.amount">
<div>
<span class="ui tiny statistic">
<span class="value">
$79.99
</span>
</span>
</div>
</div><!---->
</div>
</product-searcher-results>
On the home page there are a 30 buttons that I am trying to target. Below is my script for CasperJS.
casper.start("https://staging-shop.freedompop.com/product/", function( ) {
this.echo(this.getTitle( ) );
} );
casper.waitForSelector( '.md-card-image', function( ) {
console.log( 'AJAX results loaded' );
this.echo( this.getTitle( ) );
} )
casper.then( function( ) {
var buttons = document.querySelectorAll("product-searcher-results button");
while (buttons.length > 0) {
button = buttons.pop();
(function(button) {
casper.then(function() {
casper.echo("Button id is " + button);
});
casper.then(function() {
this.clickLabel('Details');
});
casper.waitForSelector('.md-card-image', function() {
casper.echo(casper.getCurrentUrl());
});
this.back();
})(button);
}
})
The last statement isn't running, i am trying to grab all the buttons from product search results. And I am trying to click on them one by one and getting the currentURL. I was able to find the first button using this statement, but I need to click on all the buttons on the page.
if( casper.exists( 'product-searcher-results button' ) ) {
this.echo( "found" )
}
this.clickLabel( 'Details' );
I am not sure how to convert the collection of nodelists to something that casper can iterate through.
Related
I have two lists , user can drag items from list 1 to list 2 and there is a button with text input so user can add his own input to the list 2 which will be automatically updated in my MYSQL database using axios.
This is AddItem script
addItembh(){
var input = document.getElementById('itemFormbh');
if(input.value !== ''){
// this line makes a new article with input value but no attribute :(
this.tasksNotCompletedNew.unshift({
behv_skilldesc:input.value
});
axios.post('../joborder/addAttrib', {
behv_skilldesc: input.value,
type:'behvnew',
joborder_id: this.joborder_id ,
alljobs_id: this.alljobs_id
}).then((response) => {
console.log(response.data);
}).catch((error) => {
console.log(error);
});
input.value='';
}
},
To be clear on the question : I need to assign an attribute to my new article thats getting created so I can find the text of that attrib later on deleteItem method
UPDATE :
<template>
<div class="row">
<div class="col-md-4 col-md-offset-2">
<section class="list">
<header>Drag or Add Row Here</header>
<draggable class="drag-area" :list="tasksNotCompletedNew" :options="{animation:200, group:'status',handle:'disabled'}" :element="'article'" #add="onAdd($event, false)" #change="update">
<article class="card" v-for="(task, index) in tasksNotCompletedNew" :key="task.prof_id" :data-id="task.prof_id" #change="onChange">
<span >
{{ task.prof_skilldesc }}
</span>
<span v-if="task.prof_skilldesc !== 'Drag Here'">
<button class="pull-left" #click="deleteItem(task.prof_id) + spliceit(index)" ><i class="fa fa-times inline"></i></button>
</span>
</article>
<article class="card" v-if="tasksNotCompletedNew == ''">
<span>
Drag Here
</span>
</article>
</draggable>
<div>
<input id='itemForm' />
<button v-on:click='addItem' class="btn btn-theme btn-success" style='margin-top:5px;' >Add a row </button>
</div>
</section>
</div>
<div class="col-md-4">
<section class="list">
<header>List of Skills ( Hold left click )</header>
<draggable class="drag-area" :list="tasksCompletedNew" :options="{animation:200, group:'status'}" :element="'article'" #add="onAdd($event, true)" #change="update">
<article class="card"
v-for="(task, index) in visibleskills"
:key="task.prof_id" :data-id="task.prof_id"
>
{{ task.prof_skilldesc }}
<div v-if="index == 4" style="display:none" >{{index2 = onChange(index)}}</div>
</article>
<pagination
v-bind:tasksCompletedNew ="tasksCompletedNew"
v-on:page:update ="updatePage"
v-bind:currentPage ="currentPage"
v-bind:pageSize="pageSize">
</pagination>
</draggable>
</section>
</div>
</div>
</template>
So on Add a row our method will be called .
Thanks for any help
I'm working on a system where the user can select a product and go to the next page. This product then gets saved in the session using laravel sessions. When the user decides to go to the next page and come back. The chosen product is indeed saved in the session, but the is no way for them to see what product they have chosen because the class isn't applied to the product that was chosen.
The code may clarify it better:
#foreach($themes as $theme)
<div class="col-md-4 mb-4">
<div class="card theme-card card-hover depth-2 border-0" id="theme-id-{{$theme->id}}">
<a href="" class="theme-link" data-toggle="modal" data-target="#theme{{ $theme->id }}">
<div class="card-image" style="height: 200px; background-image: url('/uploads/{{ $theme->thumbnail }}'); background-size: cover; background-position: center center;"></div>
<div class="card-body">
<div class="row">
<div class="col-md-2 vertical-center">
<i class="fab fa-magento fa-lg"></i>
</div>
<div class="col-md-10">
<p class="m-0">{!! str_limit($theme->name, $limit = 32, $end = '...') !!}</p>
<small class="text-muted">{{ $theme->productable_type }}</small>
</div>
</div>
</div>
</a>
<div class="card-footer bg-white border-0 text-right pt-0">
<div class="row">
<div class="col-md-6 text-left">
<input type="hidden" class="theme-name" name="theme[{{$theme->id}}]">
{{--<input type="hidden" value="{{ $theme->composer_package }}">--}}
<button data-card-id="{{$theme->id}}" class="btn btn-orange btn-sm btn-theme-choice">Kiezen</button>
</div>
<div class="col-md-6 text-right">
<span style="font-size: 20px;" >€ {{ $theme->price }} EUR</span>
</div>
</div>
</div>
</div>
</div>
#endforeach
In the above code, I for each trough every so-called "Theme" and I'm giving the ID of the theme as a data target and as ID. Then in my Javascript code, I do the following:
$('.btn-theme-choice').on('click', function (event) {
event.preventDefault();
newSelectedCardId = $(event.target).data('card-id');
if(cardId === null) {
cardId = newSelectedCardId;
} else if (cardId !== newSelectedCardId) {
$('#theme-id-' + cardId).removeClass('theme-chosen').find("input[name='theme["+cardId+"]']").val('');
cardId = null;
}
var card = $('#theme-id-' + cardId );
card.toggleClass('theme-chosen');
selectedCardInput = card.find("input[name='theme["+cardId+"]']");
if( !$('.theme-card').hasClass('theme-chosen') ) {
selectedCardInput.val('');
} else if ( $('.theme-card').hasClass('theme-chosen') ) {
selectedCardInput.val('selected');
}
console.log(selectedCardInput);
});
Here I add the class to the card so the user can See which card they've selected. This choice then gets saved in the session using some PHP code in the controller
if( $theme == null ) {
return redirect('plugins');
} elseif( $theme != null ) {
foreach($this->predefinedArray as $value) {
$request->session()->put('chosen_theme.' . $value, $theme->$value);
}
$request->session()->put('chosen_theme.composer_package', $theme->productable->composer_package);
return redirect('plugins');
}
problem
How can I read the session and add the class to the card with the IDs that were stored in the session so if the person leaves the page and comes back, they can see what cards they've selected?
Thanks in advance
Try this in your view..
<div class="card theme-card card-hover depth-2 border-0 {{ \Session::get('chosen_theme.composer_package') == $theme->id ? 'theme-chosen' : '' }}" id="theme-id-{{$theme->id}}">
Whenever the theme id is in the session and the page loaded the class will be added, and if it is not in the session then the class won't be added.
Let me know the result..
I have an Angular app that takes a large complex data set, and allows the user to filter it down using select lists. When data is filtered, a Google Map object is updated to display associated locations with the items that have been filtered.
I am trying to work it so that when the user clicks on a map pin, the filtered list of data is updated with only the items that are associated with that location.
Some snippets of the code:
$scope.showInfoWindow = function(event, site) {
var infowindow = new google.maps.InfoWindow();
var center = new google.maps.LatLng(site.Latitude, site.Longitude);
infowindow.setContent(
'<h3>' + site.SiteName + '</h3>' + '<p>' + site.Address1 + '<br/>' + site.Address2 + '<br/>' + site.City + ', ' + site.State + ' ' + site.ZipCode + '</p>');
infowindow.setPosition(center);
infowindow.open($scope.map);
$scope.findSelectedLocations(site.SiteName);
};
$scope.findSelectedLocations = function(SiteName) {
$scope.filteredData.forEach(function(itemElement, itemIndex) {
itemElement.Locations.forEach(function(locationElement, locationIndex) {
locationElement.Sites.forEach(function(siteElement, siteIndex) {
if (siteElement.SiteName == SiteName) {
console.log('match!');
console.log('itemIndex: ' + itemIndex);
console.table(itemElement);
$scope.$apply(function() {
$scope.filteredData == itemElement;
});
return false;
}
});
});
});
<div class="trials-item-outer-wrapper">
<div class="trials-item-wrapper" du-scroll-container>
<!-- start of row -->
<div class="trials-item {{class}}" ng-repeat="data in (filteredData = (dataObject | byCountry : selectRegion | byRegion : selectState | byCity : selectCity | filterBy:['Phase']: selectPhase | filterBy:['Compound']: selectCompound | filterBy:['TherapeuticArea', 'TherapeuticArea_2',]: selectTherapy : 'strict' | unique: 'Id' | orderBy:'Phase' : reverse)) track by $index "
ng-class="{'open':$index == selectedRow}" id="anchor-{{$index}}">
<div class="trials-item-cell-wrapper">
<div class="trials-item-cell">
<img ng-click="toggleOpen($index, data.Compound,data.Number)" ng-src="assets/img/phase{{ data.Phase}}.png" width="54" height="61" alt="Phase {{ data.Phase}}" class="trials-item-phase-icon">
</div>
<div class="trials-item-cell"><a ng-click="toggleOpen($index, data.Compound,data.Number)"><span class="compound">{{ data.Compound }}</span><br/>{{ data.Compound_2 }}</a>
</div>
<div class="trials-item-cell">
<a href="" ng-click="toggleOpen($index, data.Compound,data.Number)">
<p class="trial-title">{{ data.TitleShort }}</p>
<p>{{ data.Number }} {{ data.Status }}</p>
</a>
</div>
<div class="trials-item-cell">
<a href="" ng-click="toggleOpen($index, data.Compound,data.Number)">
{{ data.TherapeuticArea }}<span ng-if="data.TherapeuticArea_2">, {{ data.TherapeuticArea_2 }}</span>
</a>
</div>
<div class="trials-item-cell location-cell">
<span ng-if="data.Disclaimer">
<p>{{data.Disclaimer}}</p></span>
</div>
<div class="trials-item-cell cart-actions">
<div ng-if="!isInCart(data.Id)" class="add-to-cart">
<a href="" ng-click="addToCartModalOpen($index, data, data.Id)">
<img src="assets/img/cart-add.png" width="73" height="65" alt="Cart Add">
<span>Add to Cart</span>
</a>
</div>
<div ng-if="isInCart(data.Id)" class="remove-from-cart">
<a href="" ng-click="removeFromCart(data.Id)">
<img src="assets/img/cart-added.png" width="73" height="65" alt="Cart Add">
<span>Remove from Cart</span>
</a>
</div>
</div>
<div class="trials-item-cell">
<a ng-click="toggleOpen($index, data.Compound,data.Number)">
<p class="more-text"></p>
<div class="more glyphicon"></div>
</a>
</div>
</div>
<!-- trials-item-cell-wrapper -->
<div class="trials-tabs" ng-include="data.Url"></div>
</div>
<!-- end of ng-repeat -->
So the view uses the $scope.filteredData obj to display the list of filtered data. In $scope.showInfoWindow, I'm displaying an infowindow for a map pin that the user clicks on. I then pass the 'site.SiteName' value to the $scope.findSelectedLocations method to loop thru the $scope.filteredData object to find any matches to that location. This part works fine. I can console.table the data and see that itemElement is indeed showing the correct data when the map pin is click (via $scope.showInfoWindow() ).
When I'm having the issue is getting that updated data back in to the view.
In $scope.findSelectedLocations, I'm updating $scope.filteredData with the updated items in itemElement, but the view that displays $scope.filteredData isn't updating. As you can see below, I've tried wrapping that assignment in a $scope.$apply, but that doesn't work either.
No need for apply(), that's needed when something out of Angular's context needs to be rendered explicitly in a digest cycle.
May be there's a typo:
Instead of:
$scope.filteredData == itemElement;
Use:
$scope.filteredData = itemElement;
And try now.
Angular has two-way data binding. So whenever your model updates, views will automatically be get rendered. Nothing needs to be done explicitly. We have to have a watcher if we want to update the view/logic based on some change detection.
I am very new to the smart table. I have gone through its documentation on Smart Table.
But the I haven't found how to bind data on click event in smart table?
Code is very big but I am trying to post it here.
<div class="table-scroll-x" st-table="backlinksData" st-safe-src="backlinks" st-set-filter="myStrictFilter">
<div class="crawlhealthshowcontent">
<div class="crawlhealthshowcontent-right">
<input type="text" class="crserachinput" placeholder="My URL" st-search="{{TargetUrl}}" />
<a class="bluebtn">Search</a>
</div>
<div class="clearfix"></div>
</div>
<br />
<div class="table-header clearfix">
<div class="row">
<div class="col-sm-6_5">
<div st-sort="SourceUrl" st-skip-natural="true">
Page URL
</div>
</div>
<div class="col-sm-2">
<div st-sort="SourceAnchor" st-skip-natural="true">
Anchor Text
</div>
</div>
<div class="col-sm-1">
<div st-sort="ExternalLinksCount" st-skip-natural="true">
External<br />Links
</div>
</div>
<div class="col-sm-1">
<div st-sort="InternalLinksCount" st-skip-natural="true">
Internal<br />Links
</div>
</div>
<div class="col-sm-1">
<div st-sort="IsFollow" st-skip-natural="true">
Type
</div>
</div>
</div>
</div>
<div class="table-body clearfix">
<div class="row" ng-repeat="backlink in backlinksData" ng-if="backlinks.length > 0">
<div class="col-sm-6_5">
<div class="pos-rel">
<span class="display-inline wrapWord" tool-tip="{{ backlink.SourceUrl }}"><b>Backlink source:</b> <a target="_blank" href="{{backlink.SourceUrl}}">{{ backlink.SourceUrl }}</a></span><br />
<span class="display-inline wrapWord" tool-tip="{{ backlink.SourceTitle }}"><b>Link description:</b> {{ backlink.SourceTitle }}</span> <br />
<span class="display-inline wrapWord" tool-tip="{{ backlink.TargetUrl }}"><b>My URL:</b> <a target="_blank" href="{{backlink.TargetUrl}}">{{ backlink.TargetUrl }}</a></span><br />
</div>
</div>
<div class="col-sm-2">
<div class="pos-rel">
{{ backlink.SourceAnchor }}
</div>
</div>
<div class="col-sm-1">
<div>
{{ backlink.ExternalLinksCount }}
</div>
</div>
<div class="col-sm-1">
<div>
{{ backlink.InternalLinksCount }}
</div>
</div>
<div class="col-sm-1">
<div ng-if="!backlink.IsFollow">
No Follow
</div>
</div>
</div>
<div class="row" ng-if="backlinks.length == 0">
No backlinks exists for selected location.
</div>
</div>
<div class="pos-rel" st-pagination="" st-displayed-pages="10" st-template="Home/PaginationCustom"></div>
</div>
and my js code is here.
module.controller('backlinksController', [
'$scope','$filter', 'mcatSharedDataService', 'globalVariables', 'backlinksService',
function ($scope,$filter, mcatSharedDataService, globalVariables, backlinksService) {
$scope.dataExistsValues = globalVariables.dataExistsValues;
var initialize = function () {
$scope.backlinks = undefined;
$scope.sortOrderAsc = true;
$scope.sortColumnIndex = 0;
};
initialize();
$scope.itemsByPage = 5;
var updateTableStartPage = function () {
// clear table before loading
$scope.backlinks = [];
// end clear table before loading
updateTableData();
};
var updateTableData = function () {
var property = mcatSharedDataService.PropertyDetails();
if (property == undefined || property.Primary == null || property.Primary == undefined || property.Primary.PropertyId <= 0) {
return;
}
var params = {
PropertyId: property.Primary.PropertyId
};
var backLinksDataPromise = backlinksService.getBackLinksData($scope, params);
$scope.Loading = backLinksDataPromise;
};
mcatSharedDataService.subscribeCustomerLocationsChanged($scope, updateTableStartPage);
}
]);
module.filter('myStrictFilter', function ($filter) {
return function (input, predicate) {
return $filter('filter')(input, predicate, true);
}
});
But It is working fine with the direct search on textbox.
but according to the requirement I have to perform it on button click.
Your suggestions and help would be appreciated.
Thanks in advance.
You can search for a specific row by making some simple tweaks.
add a filter to the ng-repeat, and filter it by a model that you will insert on the button click, like so: <tr ng-repeat="row in rowCollection | filter: searchQuery">
in your view, add that model (using ng-model) to an input tag and define it in your controller
then pass the value to the filter when you click the search button
here's a plunk that demonstrates this
you can use filter:searchQuery:true for strict search
EDIT:
OK, so OP's big problem was that the filtered values wouldn't show properly when paginated, the filter query is taken from an input box rather then using the de-facto st-search plug-in, So I referred to an already existing issue in github (similar), I've pulled out this plunk and modified it slightly to fit the questioned use case.
I am conditionally showing and hiding elements in my app in an accordion like fashion (can be seen in this video).
The code to perform this is:
<div class="filter-menu" ng-repeat="group in Filters | orderBy: 'title'">
<div class="filter-menu-titles" ng-click="toggleGroup(group)" ng-class="{active: isGroupShown(group)}">
<i class="icon energized" ng-class="isGroupShown(group) ? '{{group.icon}}-active' : '{{group.icon}}'"></i> <span class="filter-title-text" ng-class="{orange: isGroupShown(group)}"> {{group.title}}</span>
</div>
<div class="ion-checkbox-viewport">
<span class="filter-header" ng-show="isGroupShown(group)">{{group.title}}</span>
<br />
<ion-checkbox ng-repeat="filter in group.filters | orderBy: 'name'" class="item-accordion" value="{{filter.name}}" ng-model="filter.checked" ng-change="ModifyFilter(filter)" ng-show="isGroupShown(group)">
{{filter.name}}
</ion-checkbox>
</div>
</div>
And in the controller:
$scope.toggleGroup = function(group) {
if ($scope.isGroupShown(group)) {
$scope.shownGroup = null;
} else {
$scope.shownGroup = group;
}
};
$scope.isGroupShown = function(group) {
return $scope.shownGroup === group;
};
This works perfectly on the first load of the view. However when I navigate away from the view and then come back the elements that are shown and hidden conditionally are all hidden until a scroll event is performed. When scrolling occurs the elements are shown again.
This only occurs on iOS.