Get value from ng-repeat outside of ng-repeat - angularjs

I got a header bar outside of ng-repeat:
<ion-header-bar class="headerView" ng-show="!hideAll">
<button id="shareImage" class="button button-icon icon ion-share" style="color:#fff" ng-click="shareImageTo({{originalImageSource}})"></button>
<button class="button button-outline button-light close-btn" ng-click="closeModal()">{{::actionLabel}}</button>
</ion-header-bar>
And a slidebox where images are shown:
<ion-slide ng-repeat="single in slides track by $index">
<div class="item item-image gallery-slide-view">
<img ng-src="{{single.original}}">
<input type="text" ng-model="originalImageSource" value="{{single.original}}">
</div>
</ion-slide>
{{single.original}} is an URL to an image. But this URL is not placed in the input field. It is shown when I´m deleting this ng-model statement.
If a user clicks the button #shareImage the ShareImageTo(URL) function is executed. But with an undefined value for {{originalImageSource}}.
Any thoughts on how i could pass the URL in {{single.original}} to this ShareImageTo() function?

With $ionicSlideBoxDelegate you can get the current slide index via currentIndex(). That enables you to get the URL by $scope.slides[$ionicSlideBoxDelegate.currentIndex()].original in your ShareImageTo()-method like that:
$scope.ShareImageTo = function() {
var URL = $scope.slides[$ionicSlideBoxDelegate.currentIndex()].original;
//your logic
};
Another approach would be to use ion-slide-box's directive on-slide-changed.
Template:
<ion-slide-box on-slide-changed="slideHasChanged($index)">
...
</ion-slide-box>
Controller:
$scope.slideHasChanged = function(index) {
$scope.originalImageSource = $scope.slides[index].original;
//.. some more logic
}

Just create a div that wrap around both your navbar and your slidebox, and place your ng-repeat in that div :)

Related

Filter in ng-repeat not applying

I'm working on a Ionic project which has a view that shows a scrollable list with a search input that filters the displayed results, this view is located in a template that is loaded into another view.
We noticed the search input would move with the content when the scrolling began, disappearing making it a problem when you had scrolled and wish to filter the results.
I tried to workaround this by pulling the search input outside the template and placing it above where it is loaded in the parent view.
While this renders the search input at a fixed location, even though I specified the controller that handles its logic, the filter isn't applied on the list.
Here is how my code looks on the parent view:
<ion-popover-view id="popfecha" class="fit" >
<ion-view view-title="Nuevo ReSAT">
<ion-content class="padding" data-ng-hide="activity.state.notes || activity.state.reasonShow || activity.state.product_lineShow || activity.state.account || activity.state.contact " >
<form name="form" data-ng-submit="submitForm()">
<!-- A long form -->
</form>
</ion-content>
<ion-view class="wrapper" data-ng-show="activity.state.account" >
<!-- Filter section -->
<div data-ng-controller="AccountCatalogueCtrl" class="item item-input filterSearch bar-header popupBorder borderFirstItemPopup">
<label class="item-input-wrapper">
<i class="icon ion-search placeholder-icon"></i>
<input type="text" placeholder="Search" class="form-control"
ng-model="filterText.name">
</label>
</div>
<!-- ./Filter section -->
<ion-content class="padding" data-ng-show="activity.state.account" >
<div data-ng-controller="AccountCatalogueCtrl" ng-include="'templates/account-catalogue.html'"></div>
</ion-content>
</ion-view>
<ion-content class="padding" data-ng-show="activity.state.notes" >
<div data-ng-controller="ActivityNotesCtrl" ng-include="'templates/activity-notes.html'"></div>
</ion-content>
<ion-content class="padding" data-ng-show="activity.state.reasonShow" >
<div data-ng-controller="ReasonCatalogueCtrl" ng-include="'templates/reason-catalogue.html'"></div>
</ion-content>
<ion-content class="padding" data-ng-show="activity.state.product_lineShow" >
<div data-ng-controller="ProductLineCatalogueCtrl" ng-include="'templates/product-line-catalogue.html'"></div>
</ion-content>
<ion-content class="padding" data-ng-show="activity.state.contact" >
<div data-ng-controller="ContactCatalogueCtrl" ng-include="'templates/contact-catalogue.html'"></div>
</ion-content>
</ion-view>
</ion-popover-view>
As you can see, I'm specifying the controller AccountCatalogueCtrl to the div that holds the search input and to the div that loads the template account-catalogue.html.
Here's my template:
<ion-list>
<ion-radio class="item-avatar popupBorder borderLastItemPopupIterator whiteBackground" ng-repeat="acc in accountCatalogue | orderBy:'-name' : true | filter:filterText track by acc._id"
type="item-text-wrap" ng-value="acc.name" ng-if="!acc.isDivider" ng-click="select(acc); go()" >
<img src="img/account.png">
<h2>{{acc.name}}</h2>
</ion-radio>
</ion-list>
<ion-infinite-scroll
ng-if="canLoadAccounts"
on-infinite="loadAccounts()"
distance="5%">
</ion-infinite-scroll>
I even placed a watch on the filterText object to see it was being updated, the watch did show me that the property name was changing.
This is my controller:
var mod = angular.module('starter.controllers');
mod.controller('AccountCatalogueCtrl', ['$scope', '$rootScope', '$location', '$timeout', function ($scope, $rootScope, $location, $timeout) {
$scope.select = function(acct){
$rootScope.activity.accountId = acct._id;
};
$scope.go = function ( ) {
$timeout(function(){
$scope.$emit('HideAccount');
},150);
};
// Added the lines below to see if the filter was changing
// Since in the beginning filterText doesn't exist undefined is returned
// Later when a value is placed in the input then the filterText object is created
$scope.$watch('filterText.name', function(n, o){
console.log('filter updated ' + JSON.stringify(n) + ' ' + JSON.stringify(o));
});
}]);
If I place the search input inside my template, the filter is applied, but when placed outside the filter isn't applied. Am I doing something wrong in my implementation? How can I make sure the filter applies even if the component that received it is outside the template that makes use of the filter?
I solved this issue by removing the controller from the search input, so it looked like this:
<!-- Filter section -->
<div class="item item-input filterSearch bar-header popupBorder borderFirstItemPopup">
<label class="item-input-wrapper">
<i class="icon ion-search placeholder-icon"></i>
<input type="text" placeholder="Search" class="form-control"
ng-model="filterText.name">
</label>
</div>
<!-- ./Filter section -->
I saw that I could access to filterText on my controller AccountCatalogueCtrl due to the component that shows the catalogue has access to the scope variables from the parent component that it is holding it. This way I could change the value outside AccountCatalogueCtrl and affect the filter inside the list.

ionic scroll: Prevent translate3d on parent element

I have template in my ionic app that looks something like this:
<ion-view>
<ion-content>
<div class="nav">
<span class="ion-chevron-left" ng-click="goToMonth('thisMonth', $event)"></span>
<span>{{ monthName }}</span>
<span class="ion-chevron-right" ng-click="goToMonth('nextMonth', $event)"></span>
</div>
<ion-scroll on-scroll="onScroll()" class="wide-as-needed" delegate-handle="calendarScroll" direction="x" paging="true" scrollbar-x="false" style="min-height: 215px" ng-style="scrollStyle">
...
the div with the class 'nav' contains two buttons that let the user switch between two months. The months are in the <ion-scroll> element.
This works as it should. The buttons scroll the <ion-scrol> element horizontally. But every time the buttons are used, the entire <ion-view> is scrolled vertically down by 20px - thus hiding the buttons.
I've tried changing the <ion-scroll>s inline css (with angular.element) to not include 3d transforms, but they just get re-added.
This is the function that gets called upon click - and my attempt to prevent the transform3d on the parent element
$scope.goToMonth = function(id, event){
$location.hash(id);
if(id == 'thisMonth'){
$scope.monthName = monthLabels[thisMonth];
}
else{
$scope.monthName = monthLabels[nextMonth];
}
var elm = angular.element(document.querySelector('.nav'));
var parent = angular.element(elm.parent());
console.log(parent[0].style.transform);
parent[0].style.transform = 'none';
$ionicScrollDelegate.anchorScroll(true);
};
EDIT: I've also tried using event.stopPropagation - this breaks the functionality of the <ion-scroll> element
Can anyone tell me how to prevent this behaviour?
Silly me. It turns out this was very simple to solve. I simply just needed to add scroll="false" to the <ion-content> element. No additional controller logic was needed.
So the html code above now looks like this:
<ion-view>
<ion-content scroll="false">// <-- Here I altered the html
<div class="nav">
<span class="ion-chevron-left" ng-click="goToMonth('thisMonth', $event)"></span>
<span>{{ monthName }}</span>
<span class="ion-chevron-right" ng-click="goToMonth('nextMonth', $event)"></span>
</div>
<ion-scroll on-scroll="onScroll()" class="wide-as-needed" delegate-handle="calendarScroll" direction="x" paging="true" scrollbar-x="false" style="min-height: 215px" ng-style="scrollStyle">
...

How to show preloader inside button instead text Angular JS?

I use Angular JS library ngActivityIndicator.
I tried to show preloader inside element div instead text when button is pushed:
<div ng-activity-indicator="CircledDark">
<div ng-click="Add();" class="btn shareBtn">
<div ng-view></div>
<span>Text</span>
</div>
</div>
I posted <div ng-view></div> inside and have added directive ng-activity-indicator="CircledDark" to parent element.
When I click button, I call function that display preloader:
$activityIndicator.startAnimating();
But preloader is created outside of button:
<div ng-show="AILoading" class="ai-circled ai-indicator ai-dark-spin"></div>
This is official documantation, from here I have taken example:
https://github.com/voronianski/ngActivityIndicator#directive
How to show preloader inside button instead text Angular JS?
I think the only solution is to separate your ng-view and button, at least they do something similar in their sample page. So, in your markup you could do something like this:
<div ng-click="add()" class="btn btn-default" ng-activity-indicator="CircledDark">
<span ng-show="!AILoading">Add</span>
</div>
<div ng-view ng-show="!AILoading">{{ delayedText }}</div>
And in your controller:
$scope.delayedText = "";
$scope.add = function() {
$activityIndicator.startAnimating();
$timeout(function() {
$scope.delayedText = "Here we are!";
$activityIndicator.stopAnimating();
}, 3000);
};
Here is full Demo, you can play with CSS a little so the size of the button won't change when text is replaced by icon.

Toggling Icons in Tabs in subheader

I want to be Toggling b/w two icons. For ex: When i clicked on grid icon it will show up grid data and hide List Icon.Again when i clicked on the same icon it will show up List data and hide grid Icon.
Here is my code in Tabs.html
<div menu-toggle="right" ng-hide="data.grid = !data.grid">>
And I found http://codepen.io/mhartington/pen/zxpwbK2 But it's related to Buttons.
At the same time one needs to be show and one needs to be hide,for that u can use ng-show and ng-hide
<div menu-toggle="right" ng-hide="data.grid = !data.grid">
for grid:
<div class="" ng-hide="data.grid = !data.grid">
for icon:
<div class="" ng-show="data.grid = !data.grid">
From my understanding, I think this is what you are expecting.
<ion-view view-title="Icon Sample">
<ion-header-bar>
<h1> Icon sample </h1>
</ion-header-bar>
<ion-content>
<button class="button button-icon" ng-click="toggleIcon()">
<i class="icon" ng-class="isToggled ? 'ion-ios-list-outline' : 'ion-grid'"></i>
{{buttonText}}</button>
</ion-content>
</ion-view>
and the controller code as follows:
.controller('sampleCtrl', function($scope){
$scope.isToggled = true;
$scope.buttonText = 'List';
$scope.toggleIcon = function(){
if($scope.isToggled){
$scope.isToggled = false;
$scope.buttonText ='Grid';
}
else{
$scope.isToggled = true;
$scope.buttonText ='List';
}
}
});
http://codepen.io/svswaminathan/pen/ByPKgp
Check out this codepen example to see if it fits your requirement.This has just the code to toggle the icon alternatively within a button. I believe you are able to load the data appropriately already

How to show div when link is clicked with ng-show angular js

first off, i have links from a json and display it using ng-repeat and i want to know if its best practise to load all object property (in a div) corresponding to its link and hide it so when you click a link, the corresponding div shows.
I'm thinking about the worst case scenario, were we have about a 100 links and the load all corresponding divs and hide it o_O
So this is my html:
<a href="">
<div ng-model="showModal" class="contentItem" ng-repeat='meal in recipes | filter:searchText' ng-style="{'background-image':'url({{ meal.url }})'}">
<span id="contentItemHeader">{{ meal.title }}</span>
<span id="contentItemLevel">{{ meal.level }}</span>
</div>
</a>
This is the div (modal) i want to display in full screen:
<div ng-show="showModal" ng-repeat='meal in recipes'>
<span>{{ meal.url }}</span>
<span>{{ meal.method }}</span>
<span>{{ meal.ingredients }}</span>
</div>
Use case is:
-all links loads
-click a link
-corresponding div shows
Thats it ! just like when you see a list of videos on youtube, you click one, then the video page opens but as a modal (same page)
Thanks alot,
regards
You can utilize $modal service from the UI Bootstrap, define template for meal's modal and attach ng-click handler on each individual meal in ng-repeat. In click handle you can open modal and pass meal instance to modal's scope:
View:
<div ng-repeat='meal in recipes' ng-click='selectMeal(meal)'>
{{meal.title}}
</div>
Conrtoller:
$scope.selectMeal = function(meal) {
var dialogScope = $scope.$new(true);
dialogScope.meal = meal;
var modalInstannce = $modal.open({
templateUrl: 'meal-dialog.html',
scope: dialogScope
});
};
Modal template:
<div class="modal-header">
<h3 class="modal-title">{{ meal.title }}</h3>
</div>
<div class="modal-body">
<div>{{ meal.url }}</div>
<div>{{ meal.method }}</div>
<hr />
<h4>Ingridients</h4>
<ul >
<li ng-repeat='ingridient in meal.ingridients' >{{ingridient.name}} : {{ingridient.amount}}</li>
</ul>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="$close()">Close</button>
</div>
Plunker here
To show div in question, when meal selected, introduce new selectedMeal property in $scope and use it in modal template, remove ng-repeat from modal div and set selectedMeal and showModal in selectMeal function:
$scope.selectMeal = function(meal) {
$scope.selectedMeal = meal;
$scope.showModal = true;
};
<div ng-show="showModal" >
<span>{{ selectedMeal.url }}</span>
<span>{{ selectedMeal.method }}</span>
<span>{{ selectedMeal.ingredients }}</span>
</div>
if your worried about performance of having all the divs exist, but hidden, consider using ng-if instead of ng-show. ng-if does not create the dom element if the expression is false.
<div ng-if="expression">
//element exists if 'expression' is true
</div>
if you are ok to ahead with angular-ui then i think the accordian fits the requirement perfectly... [here's the link for angular-ui's the accordian] directive 1
angular-ui is the pure angularjs implementation of all twitter bootstrap components.
<accordion close-others="oneAtATime">
<accordion-group heading="Static Header, initially expanded" is-open="status.isFirstOpen" is-disabled="status.isFirstDisabled">
This content is straight in the template.
</accordion-group>
<accordion-group heading="{{group.title}}" ng-repeat="group in groups">
{{group.content}}
</accordion-group>
</accordian>
you can have either one or all user selected link detail section open at a time...

Resources