i don't no how do i explain my question,
ok let me try,
How to pass value from another div with same controller name?
<div ng-controller="myCtrl">
<select ng-model="filterBy" ng-options="filtration.title for filtration in filter_preferences"></select>
</div>
---------------------------------------------------
<div ng-controller="myCtrl">
<select ng-model="filterBy" ng-options="filtration.title for filtration in filter_preferences"></select>
<ul>
<li ng-repeat="vals in datas | filter: vals.completed = filterBy.value">{{vals.title}}</li>
</ul>
</div>
From the second div when i filter i works fine, but the same filter i've applied on the top with same controller but it doesn't work.
DEMO PLUNKER
The problem is that under each ng-controller it's creating a new $scope. This means they don't share $scope at all, and there are two different controller instances as well.
So, to communicate between two controllers, the common practice is to use a service.
I've updated your plunk with a very basic example.
The idea is that you create a service like:
app.value('sharedData', { filteredBy: true});
Then inject it into your controller and put it on your scope like so:
app.controller('MyCtrl', function($scope, sharedData) {
$scope.sharedData = sharedData;
});
Then after that you'd use it as your ng-model value and your filter:
<select ng-model="sharedData.filteredBy" ng-options="x.value as x.title for x in filter_preferences"></select>
<ul>
<li ng-repeat="vals in datas | filter: { completed: sharedData.filteredBy }">{{vals.title}}</li>
</ul>
From there it will work because both controllers (and $scopes) now have an instance of the same object... your sharedData service.
You need to specify
ng-controller="myCtrl"
where the ng-app is and remove all the other ng-controller statements. This is because whenever you are trying to do ng-controller in individual div it is creating a local scope for that particular div and then any change in the dropdown is refreshing that local scope.
Code:
<body ng-app="myApp" ng-controller="myCtrl">
<div >
<select ng-model="$parent.filterBy" ng-options="filtration.title for filtration in filter_preferences"></select>
</div>
---------------------------------------------------
<div>
<select ng-model="$parent.filterBy" ng-options="filtration.title for filtration in filter_preferences"></select>
<ul>
<li ng-repeat="vals in datas | filter: vals.completed = $parent.filterBy.value">{{vals.title}}</li>
</ul>
</div>
</body>
Controller Code change donw:
$rootScope.filterBy = $scope.filter_preferences[1];
Earlier it was:
$scope.filterBy = $scope.filter_preferences[1];
UPDATE:
You can have the filterBy variable on the rootScope rather than the local scope. So that any changes to the local scope will be done at the root level and changes will reflect everywhere
Tried this in your plunker and it is working.
You could not mention controller twice under ng-app
Related
I have a directive in the form of a dropdown, pretty simple. The user can click a button to add as many as they need to in a ul, make their selections, and save it off. This is all inside of several ng-repeats.
I'm having trouble mastering the scope. As I expected, this works:
<div ng-repeat="group in groups" question-group="group" class="question-group">
<div ng-repeat="question in questions">
<ul>
<li ng-repeat="case in question.cases"></li>
<li><new-case group='group'></new-case></li>
</ul>
</div>
</div>
When I say "works", I mean that group is properly scoped (the data of the entire group is necessary for the resulting input).
When I switch it to "click to add":
<div ng-repeat="group in groups" question-group="group" class="question-group">
<div ng-repeat="question in questions">
<ul>
<li ng-repeat="case in question.cases"></li>
<li>add case</li>
</ul>
</div>
</div>
group is undefined in the scope. Here is my createNewCase function:
function createNewCase($event) {
var thisLi = angular.element($event.target).closest('li');
var listItem = $compile('<li><new-case group=\'group\'></new-case></li>');
var html = listItem($scope);
thisLi.before(html);
}
$scope.createNewCase = createNewCase;
And the newCase directive:
angular.module('groups.directives.newCaseDirective', [])
.directive('newCase', ['$window', function() {
return {
restrict: 'EA',
scope: { group: '=' },
templateUrl: 'groups/views/newcase.tpl.html'
};
}]);
I've been reading for days and I've tried a few other derivatives but I'm ultimately just not getting it. Help is greatly appreciated.
Thanks!
The issue is that group is created by ng-repeat and is only available in child scopes of ng-repeat.
Each repeated element is in it's own child scope. So your directive version works but your other one doesn't because the controller doesn't see those child scopes.
You would have to pass group as argument of the function if you want to access it in controller
<a href="#" ng-click="createNewCase($event, group)">
I'm trying to construct an accordion list that shows more details when the accordion expands. Here is a simplified version of the template:
<body ng-controller="MainController as main">
<accordion>
<accordion-group ng-repeat="r in main.results" ng-controller="DetailsController as d">
<accordion-heading ng-click="d.getDetails(r.id)">
{{r.name}}
</accordion-heading>
<ul>
<li ng-repeat="v in d.details">{{v.detail}}</li>
</ul>
</accordion-group>
</accordion>
</body>
The DetailsController initially has an empty details array, but when the function getDetails() is called, that array is populated by a service (detailsService is simply an abstracted $resource call). This part works when not being applied to an accordion, but in this specific situation, nothing happens with the accordion heading is clicked. See below:
app.controller('DetailsController', function(detailsService) {
var vm = this
var details = []
var detailsPopulated = false
var getDetails = function(id) {
console.log('getDetails()')
if (!vm.detailsPopulated) {
console.log('Getting details')
detailsService.get({id: id}, function(data) {
vm.details = data.results
vm.detailsPopulated = true
});
}
}
return {
details: details,
getDetails: getDetails
}
});
This controller works in other cases, but for some reason, the ng-click on the accordion header does not invoke the getDetails function at all - if it did, I would see "getDetails()" in the console, since that is the first statement of the getDetails function.
Even simpler: setting up a controller with mock "details" doesn't work.
app.controller('DetailsController', function() {
var details = [{detail: 'Test'}]
return {
details: details
}
});
Template:
<body ng-controller="MainController as main">
<accordion>
<accordion-group ng-repeat="r in main.results" ng-controller="DetailsController as d">
<accordion-heading>
{{r.name}}
</accordion-heading>
<ul>
<li ng-repeat="v in d.details">{{v.detail}}</li>
</ul>
</accordion-group>
</accordion>
</body>
Not even this simplified example with the service and ng-click removed works.
Can anyone advise a solution? I am also trying to accomplish this using the "controller as" technique instead of using $scope everywhere.
You can not bind ng-click to <accordion-heading> beacause ui.bootstrap will use different DOM for heading. You can take a look at developer console to see what ui.bootstrap translate <accordion-heading> into DOM.
<div class="panel-heading">
<h4 class="panel-title">
<span class="ng-scope ng-binding">Header 1</span>
</h4>
</div>
I think you want to dynamically load the content of accordion. One way to achieve this is to $watch when the accordion is opened and perform loading. I have created this fiddle to demonstrate the idea. Something you must notice :
You can not put ng-controller inside accordion-group because it will raise error multiple directive asking for isolated scope. This is beacause <accordion-group> is an isolated scope and angular will not allow two scope : one from controller scope and one from directive isolated scope to bind into the same html. Reference. One way to work around it is to put a div with ng-controller and ng-repeat outside accordion-group
<div ng-repeat="r in main.results" ng-controller="DetailsController as d">
<accordion-group>
...
</accordion-group>
</div>
You can add attrs is-open to accordion-group and $watch for its change and perform loading. Accordion directive will change is-open value when you open or close the accordion.
Hope it helps.
I want a live search: the results are queried from web api and updated as the user types.
The problem is that the list flickers and the "No results" text appears for a fraction of second, even if the list of results stays the same. I guess I need to remove and add items with special code to avoid this, calculating differences between arrays, etc.
Is there a simpler way to avoid this flicker at least, and probably to have possibility to animate the changes?
It looks like this now:
The html part is:
<div class="list-group">
<a ng-repeat="test in tests track by test.id | orderBy: '-id'" ng-href="#/test/{{test.id}}" class="list-group-item">
<h4 class="list-group-item-heading">{{test.name}}</h4>
{{test.description}}
</a>
</div>
<div ng-show="!tests.length" class="panel panel-danger">
<div class="panel-body">
No tests found.
</div>
<div class="panel-footer">Try a different search or clear the text to view new tests.</div>
</div>
And the controller:
testerControllers.controller('TestSearchListCtrl', ['$scope', 'TestSearch',
function($scope, TestSearch) {
$scope.tests = TestSearch.query();
$scope.$watch('search', function() {
$scope.tests = TestSearch.query({'q':$scope.search});
});
}]);
You should use ng-animate module to get the classes you need for smooth animation. For each ng-repeat item that's moved, added, or removed - angular will add specific classes. Then you can style those classes via CSS or JS so they don’t flicker.
An alternative way of doing what you require is to use the angular-ui bootstrap Typeahead component (check at the bottom of the post). It has a type-ahead-wait property in milliseconds and also a template url for customising it.
<div ng-app>
<div ng-controller="MyController">
<input type="search" ng-model="search" placeholder="Search...">
<button ng-click="fun()">search</button>
<ul>
<li ng-repeat="name in names">{{ name }}</li>
</ul>
<p>Tips: Try searching for <code>ann</code> or <code>lol</code>
</p>
</div>
</div>
function MyController($scope, $filter) {
$scope.names = [
'Lolita Dipietro',
'Annice Guernsey',
'Gerri Rall',
'Ginette Pinales',
'Lon Rondon',
'Jennine Marcos',
'Roxann Hooser',
'Brendon Loth',
'Ilda Bogdan',
'Jani Fan',
'Grace Soller',
'Everette Costantino',
'Andy Hume',
'Omar Davie',
'Jerrica Hillery',
'Charline Cogar',
'Melda Diorio',
'Rita Abbott',
'Setsuko Minger',
'Aretha Paige'];
$scope.fun = function () {
console.log($scope.search);
$scope.names = $filter('filter')($scope.names, $scope.search);
};
}
I am new to angularjs and just started learning it. I am trying to build a dropdown equivalent from angularjs without using select.
Html
<div ng-app="App" ng-controller="OrderExportCtrl" >
<li class="box-ddl" >
<div ng-model="fruit" ng-options="f for f in fruits" class="ddlListSmall">
</div>
</li>
JavaScript
var app = angular.module('App', []);
app.controller('OrderExportCtrl', function ($scope) {
$scope.fruit = ['apple', 'orange', 'mango', 'grapefruit', 'banana', 'melon'];
});
Please find the JsFiddle here. I am not getting what mistake I am doing, but my dropdown is not binding.
Please guide me to fix my issue.
ngOptions is only for select elements (it is used by the select directive). You can use ngRepeat to achieve the same result. You can use ngClick to set your model directly.
<div class="list">
<div class="option" ng-repeat="f in fruits" ng-bind="f"
ng-click="fruit.selected = f"></div>
</div>
Make sure the value you're setting is inside an object that is defined in the controller, otherwise you'll just set it inside the row's scope rather than the controller's. Alternatively use ng-click="$parent.fruit = f" to reference the parent scope, which in this case is the controller's (but may not always be).
I'd like to do something like this. The use case is I am showing a table with a configurable set of columns, each of which may have a filter associated with it. See this fiddle.
<div ng-app="">
<div ng-controller="MyCtrl">
{{money | filterStr}}
</div>
</div>
function MyCtrl($scope) {
$scope.money = 33;
$scope.filterStr = 'currency:"USD$"';
}
So as you can see, I basically want to store the filter string text as a scope variable, and then refer to it in the html by its name. This doesn't work, but is there a way to do something like this?
If you absolutely needed to save a reference to the filter dynamically within your controller $scope, you could create a reference to the filter function within a controller variable and then call it in the HTML like you would any other function or you could run the filter on your data in your controller and save the output to a variable. Here are two examples of doing this with the currency filter (JS Fiddle here):
<div ng-app="">
<div ng-controller="MyCtrl">
{{ moneyWithFilter }}
{{ currencyFilter(money, "USD$") }}
</div>
</div>
function MyCtrl($scope, currencyFilter) {
$scope.money = 33;
$scope.moneyWithFilter = currencyFilter($scope.money, "USD$");
$scope.currencyFilter = currencyFilter;
}
Notice that you have to append the string 'Filter' to the desired filter in order to inject it into your controller. You can read more about that here. I hope this helps!
I do something like this with
<a ng-click="setCurrent(m)">
{{m.name}}
</a>
<p ng-repeat="L in List | filter:current.name">
<a ng-click="add(w)">
{{w.Name}}
</a>
</p>
Then
function setCurrent(m) {
$scope.current = m;
}