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.
Related
I am creating app in ionic /angularjs.
The controller fetches the data in JSON format from the URL and displays unique images in div elements. I want to allow these images to be clicked and then display the data according to offer_name, which is coming from the JSON data.
e.g.: Suppose I display the image for Amazon (in background offer_name is amazon (having 10 records)). When the user clicks on that, it displays all the records related to amazon.
Hope you get my point but no database is included; it only works with JSON data.
Also, how can the check current value be checked in ng-repeat?
Here is my code:
.controller('menuCtrl', function($scope,$http) {
$http.get("http://tools.vcommission.com/api/coupons.php?apikey=e159f64e3dd49fddc3bb21dcda70f10c6670ea91aac30c7cb1d4ed37b20c45b8").then(function (response) {
$scope.myData = response.data;
/* $scope.stack=[];
angular.forEach($scope.myData, function(item){
$scope.stack =item.store_image;
var uni_img=[];
for(var i=0 ; i< $scope.stack.length;i++)
{
if(uni_img.indexOf($scope.stack[i] == -1))
uni_img.push($scope.stack[i]);
}
console.log(uni_img);
})*/
});
$scope.dealopen = function($a){
for (var i=0;i<$scope.myData.length;i++)
{
//console.log($scope.data[i].name);
$link=$scope.data[i].offer_name;
if ($link==$a)
{
$window.open($link,"_self","location=yes");
console.log($a);
}
}
}
})
Html
<div class="item col-sm-2 col-sm-3 col-md-2 " ng-repeat="da in myData | unique: 'store_image'" >
<div class="thumbnail">
<img class="thumbnail img-responsive " ng-src="{{ da.store_image}}"
/>
<div class="caption">
<b class="group inner list-group-item-heading center-block">
{{da.offer_name | limitTo: 12 }} Deals</b>
<a class="item item-text-wrap" ng-href="#/Deals/{{da.offer_name}}">View Deal</a>
</div>
</div>
</div>
Here is the output:
.
One way to achieve this is to use ng-click to execute javascript (e.g. inline or call a function in the controller scope. Per the documentation for ngRepeat $index can be referenced for the current index:
Special properties are exposed on the local scope of each template instance, including:
+----------+---------+-----------------------------------------------------------------------------+
| Variable | Type | Details |
+----------+---------+-----------------------------------------------------------------------------+
| $index | number | iterator offset of the repeated element (0..length-1) |
| $first | boolean | true if the repeated element is first in the iterator. |
| $middle | boolean | true if the repeated element is between the first and last in the iterator. |
| $last | boolean | true if the repeated element is last in the iterator. |
| $even | boolean | true if the iterator position $index is even (otherwise false). |
| $odd | boolean | true if the iterator position $index is odd (otherwise false). |
+----------+---------+-----------------------------------------------------------------------------+
1
So the image tag can have the attribute ng-click to utilize that directive, like this:
<img class="thumbnail img-responsive " ng-src="{{ da.store_image}}" ng-click="showData(da.offer_name, $index)"/>
Then use Array.filter() to filter all offers into a filtered array of offers matching the offer_name:
$scope.showData = function (offer_name, index) {
$scope.offerName = da.offer_name;
$scope.filteredOffers = $scope.myData.filter(function(offer) {
return offer.offer_name == $scope.offerName;
});
}
And then add another set of elements to display the items in filteredOffers.
<div ng-repeat="offer in filteredOffers">
<div class="couponCode">{{offer.coupon_code}}</div>
<div class="couponTitle">{{offer.coupon_title}}</div>
<div class="couponDescription">{{offer.coupon_Description}}</div>
</div>
See the example below where the showData function updates the model selectedIndex, offerName and filteredOffers using these components.
angular.module('myApp', ['ui'])
.controller('menuCtrl', ['$scope', '$http',
function($scope, $http) {
$scope.offerName = ''; //set initially
$scope.selectedIndex = -1;
$scope.filteredOffers = [];
$http.get("http://tools.vcommission.com/api/coupons.php?apikey=e159f64e3dd49fddc3bb21dcda70f10c6670ea91aac30c7cb1d4ed37b20c45b8").then(function(response) {
$scope.myData = response.data;
});
$scope.showData = function(offer_name, index) {
$scope.offerName = offer_name;
$scope.filteredOffers = $scope.myData.filter(function(offer) {
return offer.offer_name == $scope.offerName;
});
$scope.selectedIndex = index;
}
}
]);
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js" data-semver="1.1.5" data-require="angular.js#*" context="anonymous"></script>
<script data-require="angular-ui#*" data-semver="0.4.0" src="//rawgithub.com/angular-ui/angular-ui/master/build/angular-ui.js" context="anonymous"></script>
<div ng-app="myApp" ng-controller="menuCtrl">
<div>
OfferName:
<span ng-bind="offerName"></span>
</div>
<div>
selected index:
<span ng-bind="selectedIndex"></span>
</div>
<div class="item col-sm-2 col-sm-3 col-md-2 " ng-repeat="da in myData | unique: 'store_image'">
<div class="thumbnail">
<img class="thumbnail img-responsive " ng-src="{{ da.store_image}}" ng-click="showData(da.offer_name, $index)" />
<div class="caption">
<b class="group inner list-group-item-heading center-block">
{{da.offer_name | limitTo: 12 }} Deals</b>
<a class="item item-text-wrap" ng-href="#/Deals/{{da.offer_name}}">View Deal</a>
</div>
</div>
</div>
<div ng-repeat="offer in filteredOffers">
<div class="couponCode">{{offer.coupon_code}}</div>
<div class="couponTitle">{{offer.coupon_title}}</div>
<div class="couponDescription">{{offer.coupon_Description}}</div>
</div>
</div>
1 https://docs.angularjs.org/api/ng/directive/ngRepeat
You can use $index, that is the variable used in agular to know the index position in ng-repeat, if you want to know more about another contro variables of ng-repeat read the docs in the next link https://docs.angularjs.org/api/ng/directive/ngRepeat
An basic example is.
CONTROLLER
app.controller('menuCtrl', function($scope,$http) {
$scope.myData = [{path:'http://www.imagefree1.com',info:'http://www.infoimage1.com'},
{path:'http://www.imagefree2.com',info:'http://www.infoimage2.com'},
{path:'http://www.imagefree3.com',info:'http://www.infoimage3.com'}];
$scope.callDetail=function(index)
window.open(myData[index].info);
})
HTML
<div ng-repeat="image in myData">
<a href="#" ng-click="callDetail($index)">
<img src="image.path" alt="Description"/>
</a>
</div>
At first look you never call the $scope.dealopen function,
may be this can work....
<div class="item col-sm-2 col-sm-3 col-md-2 " ng-repeat="da in myData | unique: 'store_image'" >
<div class="thumbnail">
<img class="thumbnail img-responsive " ng-src="{{ da.store_image}}"/>
<div class="caption">
<b class="group inner list-group-item-heading center-block">{{da.offer_name | limitTo: 12 }} Deals</b>
<a class="item item-text-wrap" ng-click="dealopen(da.offer_name)">View Deal</a>
</div>
</div>
</div>
I have no idea how to write the title in a more understandable way. So bear with me.
I have tags. I have posts
Each post has 2 or 3 or more associated tags.
My aim:
To list all the tags and to list all the specific posts underneath those tags.
Here's a clear picture
Tag1
Post1 Post2 Post3
Tag2
Post4 Post1
Tag3
Post3
Ok. Now, I'm using two functions in my controller to do this job.
One is to get the list of tags and other is to get the posts for each tag.
Hereafter,
$scope.tags = null;
$scope.tagPosts = null;
var getTags = function(callback){
$http.get('/tags').success(function(result){
$scope.tags = result;
callback();
}).error(function(e){
console.log(e);
});
};
var getPostsByTags = function(){
for(var i = 0; i < $scope.tags.length; i++){
var currentTag = $scope.tags[i];
$http.get('/posts/tag/' + currentTag.name).success(function(result){
$scope.tagPosts = result;
// Printing all the posts correctly
console.log($scope.tagPosts);
}).error(function(e){
console.log(e);
});
}
}
getTags(function(){
getPostsByTags();
});
And in the view
<div class="single-list" style="padding-bottom: 10px;" ng-repeat="tag in tags">
<h3 style="border-bottom: 3px solid #e2e2e2; padding-bottom:10px;">{{ tag.name }} ( {{ tag.used }} )</h3>
<div>
<ul class="list-group">
<li class="list-group-item" ng-repeat="post in tagPosts">
<span>
{{ post.title }}
</span>
<span class="pull-right">{{ post.date }}</span>
</li>
</ul>
</div>
</div>
So I'm printing all the tags first then printing the posts associated with each tag. Here, I have used ngRepeat twice. The problem is it's only printing the last post from my database under each tag and not the rest though it's consoling out all the posts in the correct order.
This is because, in $scope.tagPosts it's replacing the result with new result till the last iteration where only a single post is associated with the last tag
So, is it possible to trigger the second ng-repeat after every for loop completion? Or is it possible to do something with the $scope.tagPosts or any other tricks?
Hope I made the problem clear.
You could do it with a filter like this:
In your js:
$scope.postsToFilter = function(){
indexedPosts = [];
return $scope.posts;
}
$scope.filterPosts =function(post){
var postIsNew = indexedPosts.indexOf(post.tagname) == -1;
if(postIsNew){
indexedPosts.push(post.tagname)
}
return postIsNew;
}
And in your HTML:
<div ng-repeat="t in postsToFilter() | filter:filterPosts">
<h1>{{t.tagname}}</h1>
<div ng-repeat="p in posts | filter:{tagname: t.tagname} : true">
{{p.name}}
</div>
</div>
Here is a Plunker. I believe this is what you are trying to do. Let me know if it is not.
I believe your problem is in the way you are assigning the result to $scope.tagPosts. It is an array thats why it should be appended a new result not directly assigned.
Try this:
$scope.tagPosts = []; // at the beginning of controller
....
$scope.tagPosts.push(result); // inside your for loop
UPDATE
From the result, seems like tagPosts is an array of arrays! That's why you will need to do another ng-repeat:
<li class="list-group-item" ng-repeat="post_arr in tagPosts">
<span ng-repeat="post in post_arr">
<span>
{{ post.title }}
</span>
<span class="pull-right">{{ post.date }}</span>
</span>
</li>
Try this:
(1) In your controller it should be
var getPostsByTags = function(){
for(var i = 0; i < $scope.tags.length; i++){
var currentTag = $scope.tags[i];
$http.get('/posts/tag/' + currentTag.name).success(function(result){
currentTag.tagPosts = result;
// Printing all the posts correctly
console.log($scope.tagPosts);
}).error(function(e){
console.log(e);
});
}
}
(2) In the view, replace the
<div class="single-list" style="padding-bottom: 10px;" ng-repeat="tag in tags">
<h3 style="border-bottom: 3px solid #e2e2e2; padding-bottom:10px;">{{ tag.name }} ( {{ tag.used }} )</h3>
<div>
<ul class="list-group">
<li class="list-group-item" ng-repeat="post in tag.tagPosts">
<span>
{{ post.title }}
</span>
<span class="pull-right">{{ post.date }}</span>
</li>
</ul>
</div>
</div>
I think the problem here is the inner ng-repeat loop traverse the variable $scope.tagPosts, which is updated by every ajax call that get post from backend. So after all ajax call finished, this variable is been updated as the value of posts with last tag, so you only see the post with the last tag in tag array.
I believe an array will solve your problems, where each element is of type {tag:TagObject,posts:PostObject[]}.For an example:
$scope.data =[]
var getTags = function(callback){
$http.get('/tags').success(function(result){
$scope.tags = result;
callback();
}).error(function(e){
console.log(e);
});
var getPostsByTags = function(){
for(var i = 0; i < $scope.tags.length; i++){
var currentTag = $scope.tags[i];
$http.get('/posts/tag/' + currentTag.name).success(function(result){
$scope.data.push({tag:currentTag,posts:result});
// Printing all the posts correctly
console.log($scope.tagPosts);
}).error(function(e){
console.log(e);
});
}
and in your html:
<div class="single-list" style="padding-bottom: 10px;" ng-repeat="tag in data">
<h3 style="border-bottom: 3px solid #e2e2e2; padding-bottom:10px;">{{ tag.tag.name }} ( {{ tag.tag.used }} )</h3>
<div>
<ul class="list-group">
<li class="list-group-item" ng-repeat="post in tag.posts">
<span>
{{ post.title }}
</span>
<span class="pull-right">{{ post.date }}</span>
</li>
</ul>
</div>
</div>
Haven't tested the above but i think it looks ok
I want to show data using ng-click
First i have listing for of all the companies, this works fine. it displays all the companies.:
<div class="col-xs-3" ng-repeat="item in companyData">
<a ng-click="getPackageInfo({id:item.iCompanyID})" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vCompanyName}}</span>
</a>
</div>
Now on click of company name, i have to display other info like packges of that company, for that i have done this under above div:
<div ng-repeat="item in pData" class="col-xs-3">
<a ng-click="" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vPackageName}}</span>
</a>
</div>
In controller.js i did this, getPackageInDetail will return package listing according to company id:
function getPackageInfo(id) {
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function(data) {
$scope.pData = data;
}).
error(function(data,status,header,config) {
$scope.pData = 0;
});
};
How can i append the data according to company clicked?
Array.prototype.push.apply() can be used for merging two arrays.
Merge the second array into the first one
//Define an empty array
$scope.pData = [];
$scope.getPackageInfo = function(id) {
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function(data) {
Array.prototype.push.apply($scope.pData, data); //Merge the array
});
};
Additionally, I think you need to pass ID properly
<a ng-click="getPackageInfo(item.iCompanyID)">
I have a main form with the following markup
<tabset vertical="true" type="pills">
<tab ng-repeat="tab in tabsViews" select="selectView(tab.name, tab.index)"
ng-show="tab.isVisible"
class=" {{tabsViews[tab.index-1]['invalid'] ? 'invalid-tab': 'valid-tab' }}">
<tab-heading>{{tab.title}}</tab-heading>
</tab>
</tabset>
and the selectView method in my controller is the following:
$scope.previousIndex = null;
$scope.selectView = function (viewName, viewIndex) {
$scope.selections.showInvoicesDetailView = false;
$scope.selections.showInvoicesView = false;
$scope.selections.showPassesView = false;
if (viewIndex) {
if ($scope.previousIndex != null && $scope.form) {
$scope.tabsViews[$scope.previousIndex - 1]["invalid"] = $scope.form.$invalid;
}
$scope.previousIndex = viewIndex;
}
if (viewName.substring(0, 9) != 'invoices.')
$scope.selections.lastSelectedView = viewName;
else
$scope.selections.showInvoicesDetailView = true;
if (viewName == 'guestPasses')
$scope.selections.showPassesView = true;
if (viewName == 'invoices')
$scope.selections.showInvoicesView = true;
if ($scope.selections.isNew) {
window.console && console.log('SelectView called with the new.' + viewName + ' view...');
$state.go('new.' + viewName);
}
else {
window.console && console.log('SelectView called with the edit.' + viewName + ' view...');
$state.go('edit.' + viewName);
}
};
The main form has a directive to detect its dirty state and ask for saving the changes. The problem is that when I change anything in my current view, that form's dirty state is not propagated into that main form. Is there a way to set main form dirty state based on the particular tab (defined as the view) dirty state?
To understand the problem better, here is the main form markup (the one that has tabs):
div ng-class="{'col-md-7': $parent.showSearch, 'col-md-11': !$parent.showSearch}">
#Html.Partial("_EditFormHeader")
<div class="fourpanel">
<div data-sm:collapse="$parent.showForm" id="hideFrm" class="pull-left col-sm-3 sm-search-list">
<form name="guestMainForm" novalidate role="form" data-sm:dirty-check data-server:error
ng-show="$parent.showForm && !selections.justDeleted" class="ng-cloak">
<div id="guestEditForm" class="widget" data-resize:container>
<div class="widget-head">
<div class="row">
<div class="clearfix"></div>
#Labels.guest: {{currentGuest.contactPerson.firstName + ' ' + currentGuest.contactPerson.lastName}} {{ !isNew ? '(' + currentGuest.guestNo + ')' : '' }}
<div class="pull-right text-right col-lg-1" style="padding-right:5px">
<i class="fa fa-angle-double-left sm-slider-button" ng-click="toggleFormVisibility()"
alt="#String.Format(Labels.hideX, Labels.account)" id="angle-left"></i>
</div>
</div>
</div>
<div class="widget-content">
<div class="scrollable widget-resize">
<div class="padd">
#Html.Partial("_EditFormAlerts")
</div>
<div class="col-lg-2 col-md-2 panel-container">
<tabset vertical="true" type="pills">
<tab ng-repeat="tab in tabsViews" select="selectView(tab.name, tab.index)"
ng-show="tab.isVisible"
class=" {{tabsViews[tab.index-1]['invalid'] ? 'invalid-tab': 'valid-tab' }}">
<tab-heading>{{tab.title}}</tab-heading>
</tab>
</tabset>
</div>
<div class="col-lg-8 col-md-4 panel-container">
<div data-ui-view data-autoscroll="false"></div>
<div data-ui-view="guestPasses" ng-show="selections.showPassesView"></div>
<div data-ui-view="invoices" data-autoscroll="false" ng-show="selections.showInvoicesView"></div>
</div>
</div>
</div>
<div class="widget-foot">
<div ng-show="!isNew">
<button class="btn btn-primary" ng-click="save(currentGuest)"
ng-disabled="form.$invalid || disableAction">
#Labels.save
</button>
<data-delete:button title="{{ '#Labels.delete: ' + currentGuest.contactPerson.firstName.trim() + ' ' + currentGuest.contactPerson.lastName.trim() + ' (' + currentGuest.guestNo +')' }}"
message="#String.Format(Messages.confirmDelete, Labels.guest)"
disable-action="disableAction"
delete="delete()">
</data-delete:button>
<data-cancel:button title="#Labels.unsavedChanges"
message="#Messages.unsavedChanges"
cancel="cancel()"
disable-action="disableAction"
dirty="form.$dirty">
</data-cancel:button>
</div>
<div ng-show="isNew">
<button id="btnAdd" class="btn btn-primary" ng-click="new(currentGuest)"
ng-disabled="form.$invalid || disableAction">
#Labels.add
</button>
<data-cancel:button title="#Labels.unsavedChanges"
message="#Messages.unsavedChanges"
cancel="cancel()"
disable-action="disableAction"
dirty="form.$dirty">
</data-cancel:button>
</div>
</div>
</div>
</form>
</div>
<div id="showFrm" class="sm-form-expand-button text-center col-sm-1"
ng-show="!$parent.showForm"
ng-click="toggleFormVisibility()">
<i class="fa fa-angle-double-right"></i>
<div class="panel2Label">#Labels.guest: {{ currentGuest.contact.firstName.trim() + ' ' + currentGuest.contact.lastName.trim() }} {{ !isNew ? '(' + currentGuest.guestNo + ')' : '' }}</div>
</div>
<div class="col-sm-5 panel-container">
<div data-ui-view="detail" data-autoscroll="true" ng-show="selections.showInvoicesDetailView"></div>
<div data-ui-view="passDetail"></div>
</div>
</div>
</div>
I created a new directive and added it to my view forms:
function ($modal, $rootScope, $location, $state) {
return {
restrict: 'A',
require: ['^form'],
//scope: {
// onOk: '&',
// onCancel: '&'
//},
link: function (scope, element, attrs, controllers) {
var form = controllers[0];
window.console && console.log(form);
window.onbeforeunload = function () {
if ((form && form.$dirty) || element.hasClass('ng-dirty')) {
// return resourceFactory.getResource('Messages', 'unsavedChanges');
if (scope.form)
{
scope.form.$setDirty();
}
}
};
}
};
I am debugging and I can see that form is correctly set to my view's form and I can access the parent form using form.$$parentForm property. However, I don't know to which event should I hook to set form.$$parentForm.$setDirty when my form becomes dirty. If you can help me figure this out, then it will work for me, I guess.
Quote from Angular documentation on the form directive:
In Angular, forms can be nested. This means that the outer form is valid when all of the child forms are valid as well. However, browsers do not allow nesting of elements, so Angular provides the ngForm directive which behaves identically to but can be nested. This allows you to have nested forms, which is very useful when using Angular validation directives in forms that are dynamically generated using the ngRepeat directive. Since you cannot dynamically generate the name attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an ngForm directive and nest these in an outer form element.
Maybe this also works for the $dirty state so that if a child form is $dirty the parent form will also be $dirty. I'm not sure that in your case you'll be able to nest the forms. I don't have enough context to visualise what you want to achieve.
Alternatively, you can manually set the main form to dirty when one of those other forms becomes dirty. Because you added the code from your main form, I can see you're not using the built in dirty checker from angular. Maybe you have a good reason for this, but perhaps you didn't know of it's existence. You'll have to use the angular form directive then. The FormController has the following method: $setDirty();.
FormController documentation
Form Directive documentation
I created a list that is searchable with an input using angular.js (ng-model="searchText"). On click of the list elements you can pull the content of the selected item using {{selected | json}}. I want to apply this selected element as the value of the input when a list item is clicked.
I essentially want to create my own autocomplete that always displays a list of options, filters options while typing, and fills in the input on click of an option.
HTML
<html ng-app>
<section>
<div id="content-body" class="container search-page"><!-- begin content-body -->
<div id="content-frame" class="container"></div><!-- end content-frame -->
<section>
<div class="search-container">
<div class="search-wrapper">
<input type="search" class="input-from" autocomplete="off" placeholder="Search" ng-model="searchText" value="{{searchText}}">
</div>
</div>
</section>
<section>
<div ng-controller="ContentCtrl">
<ul class="list-group search">
<!--<li class="list-group-item group-title">
<span class="icon itinerary-icon"></span>
Popular Destinations
</li>-->
<a ng-click="setMaster(cities)" ng-repeat="city in cities | filter:searchText | limitTo:limit" href="#" class="list-group-item">{{city}}</a>
</ul>
</div>
</section>
</div><!-- end content-body -->
</html>
JS
function ContentCtrl($scope, $http) {
"use strict";
$scope.url = '../mobile-site/cities.json';
$scope.cities = [];
$scope.limit = 10; // max 10 cities loaded
$scope.fetchContent = function() {
$http.get($scope.url).then(function(response){
$scope.cities = response.data.cities;
});
}
$scope.fetchContent(); // build cities list
$scope.setMaster = function(city) {
$scope.searchText = city; // pull selected city using {{selected | json}}
}
}
JSON
{
"version": "082B6AF45261B81358E8F99F0FAEC4A4",
"cities": [
"A Friela Maside, Spain",
"A Gudina, Spain",
"AHA, Germany",
"AL, Norway"
]
}
I think you have a few mistakes in the code:
<div ng-model="chosen">
<a ng-click="setMaster(cities)" ng-repeat="cities in cities | filter:searchText | limitTo:limit" href="#" class="list-group-item">{{cities}}</a>
</div>
shoud be
<div ng-repeat="city in cities | filter:searchText | limitTo:limit">
<a ng-click="setMaster(city)" class="list-group-item">{{city}}</a>
</div>
then I think what you want is
$scope.setMaster = function(city) {
$scope.searchText = city;
}
Also, I'm not sure what the ng-model on the div is for, as far as I know it is used only for inputs, textareas and selects. See http://docs.angularjs.org/api/ng.directive:ngModel.
You probably want something like this fiddle -> http://jsfiddle.net/weSpW/3/.