I have a directive that look like this:
<div ng-controller="searchController" searchbar>
<input type="text" id="searchfield" ng-model="myVar">
<div searchresult>
<div ng-repeat="data in data.menu | filter: myVar">
{{data.title}}
</div>
</div>
</div>
There is one controller called searchController, and 2 directives called searchbar and searchresult.
How can I have the searchbar directive to run a function in searchresult directive? I was thinking to put require: "^searchresult" in searchbar directive and call it's function. Is that the correct way of doing? What if the searchresult is not available there?
Here is the detail scenario:
When user type in the input field, the search result update by the filter. Therefore the height of searchresult div is changed.
How can the searchresult directive knows about the changes of the height & run the required function instantly?
searchResult can have reference to searchBar not the other way around. As from documentation
^ - Locate the required controller by searching the element and its
parents. Throw an error if not found.
Also look at ^? for optional dependencies. See compile documentation.
If you detail your scenario, we can help better.
Update: Based on the scenario that you have outlined, you can directly watch myVar property in searchresult directive and whenever it changes you can trigger the function to resize the results.
Assuming that the searchresult directive does not create isolated scope. You can try, such a code inside your directive link function
scope.$watch('myVar',function(newValue) {
$timeout(function() {
//do some work here
},0);
});
Timeout helps as we cannot be sure when the rendering of the list is complete.
Related
I have a directive and it works fine in a way such that when I type something the search() scope function inside my directive fires and sets $scope.query with the input text.
here is the directive template
<div class="container">
<div class="system-filter-header">
<div class="no-gutter">
<div class="system-search-wrapper search-wrapper-width">
<i ng-click="search($evt)" class="fa fa-search"></i>
<input type="text" ng-keyup=search($evt) class="search pull-left suggesstions-styles"
ng-model="query" ng-attr-placeholder="Search...">
</div>
</div>
</div>
</div>
here is the scope function which gets triggered
$scope.search = function() {
console.log($scope.query.length)
}
But when I used an ng-if="true" in first line of template (true used for generalizing only, I want to do a different conditional check inside ng-if) such that,
<div class="container" ng-if="true">
still the search gets triggered but the console.log gives always 0 and it doesn't seem to update the $scope.query value as it stays as $scope.query = ''
throughout the typing.
EDIT
Here is a an example codepen with almost similar behaviour. The problem is with the searchBox directive and I have added ng-if=true to the template but searching doesn't work. When I remove the ng-if searching works fine.
Any reason for this?
Rule of thumb in AngularJS: your ng-model should always include a dot. Otherwise AngularJS directives that create child scopes (like ng-if or ng-repeat) will create a duplicate property on that child scope instead of the parent scope. Following the controllerAs convention completely mitigates this behavior.
I'a got a template with a directive using objects. That directive modifys an elements in the objects list. I can see the object modification in the template but not inside the directive.
I used angularjs 1.5.8
My template :
<div>
<ul>
<li data-ng-repeat="event in vm.events">
// some html code about event object
</li>
</ul>
<event-directive data-events="vm.events"/>
</div>
The directive template :
<div>
<div data-ng-repeat="event in events" class="event">
<a data-ng-click="edit(event)">Edit</a>
// some detail about event
</div>
</div>
The directive is declared liked that :
function eventDirective(/* dependencies */) {
return {
template: eventTemplate,
scope: {
events: '='
}
}
}
If I modified and event in my directive I can see changes in the main template ng-repeat loop but the changes are not "propagated" to the directive.
I'm sure I'm doing someting wrong or forgot something as there's similar code in my project that works as expected.
I search for advises or way to solve my problem.
I try to simplify my code but if it's not clear or there's missing information, just tell me.
Thanks in advance for any help.
How do I go about create an element in my controller? e.g. on a click event?
example controller:
function AddCtrl($scope){
$scope.add = function(){
// do stuff to create a new element?
}
}
example view:
<div ng-controller="AddCtrl">
<button ng-click="add()">Add</button>
// create <input type="text" ng-model="form.anotherField">
</div>
Any suggestions much appreciated.
AngularJS is intended to follow MVC - so the controller creating an element in the view doesn't agree with the MVC behavior. The controller should not know about the view.
It sounds as if you want to have a control appear based on some conditional logic. One approach would be to bind to the visibility of the element.
In Angular, your controllers should not be manipulating the DOM directly. Instead, you should describe the elements you need in your templates, and then control their display with directives, like ng-switch, ng-hide / ng-show, or ng-if, based on your model, ie, your data.
For example in your controller you might do something like:
$scope.showForm = false;
And then in your partial:
<div id="myForm" ng-show="showForm">
<!-- Form goes here -->
</div>
By switching $scope.showForm between true and false, you will see your myForm div appear and disappear.
This is a classical mistake coming from jQuery moving to Angular or any other MVC library. The way you should think is to let the view react to changes in the scope.
$scope.items = []
$scope.add = function(){
$scope.items.push({});
}
In the view:
<input type="text" ng-repeat="item in items" ng-model="item.property">
If you want to display an element based on some condition or after the click, use ng-switch: http://docs.angularjs.org/api/ng/directive/ngSwitch
If you want to add multiple elements, create a repeated list of items and add an item to your view-model on clicking the button:
$scope.yourlistofitems = [];
$scope.add = function() {
$scope.yourlistofitems.push("newitemid");
}
And in the HTML:
<input type="text" ng-repeat="item in yourlistofitems" ng-model="item.property">
I want to use the angular's ng-repeat filter like so:
<div ng-repeat="trade in trades | filter:searchTrades | orderBy:predicate:reverse">
the problem here is the input control where I want to bind "searchTrades" to exists OUTSIDE the controller and view where the ng-repeate exists. the input field exists outside the controller for a good reason. it's a global search input that i intend to use differently with each controller. so further more I will need to give the search input different behavior depending on which controller/view is active.
This is a question of scopes, and eventing between scopes. As angular uses prototype inheritance, you can still gain access to "parent" scope properties and react to them.
The short of it, if you have searchTrades on a parent controller, the child controller can access it. Note if the child controller modifies searchTrades it will make a "new copy", if you need to do that use $scope.$emit and $scope.$on
Here is a plunker to look at
Consider the following
Controllers
function MainCtrl($scope, ...) {
$scope.search = 'My search term'
}
function ChildCtrl1($scope, ...) {
$scope.items = ['Foo', ... ]
}
View
<body ng-controller="MainCtrl">
<label>Search</label> <input ng-model="search" />
<div ng-controller="ChildCtrl1">
<ul>
<li ng-repeat="item in items | filter:search">{{item}}</li>
</ul>
</div>
</body>
ChildCtrl1 will inherit search from the parent controller, and it can be used as "normal"
I have multiple elements with the same callback on ng-click:
<button ng-click="doSomething()"></button>
<button ng-click="doSomething()"></button>
<button ng-click="doSomething()"></button>
<button ng-click="doSomething()"></button>
// In controller:
$scope.doSomething = function() {
// How do I get a reference to the button that triggered the function?
};
How can I get the reference to the object which made the call to doSomething? (I need to remove an attr from it)
While you do the following, technically speaking:
<button ng-click="doSomething($event)"></button>
// In controller:
$scope.doSomething = function($event) {
//reference to the button that triggered the function:
$event.target
};
This is probably something you don't want to do as AngularJS philosophy is to focus on model manipulation and let AngularJS do the rendering (based on hints from the declarative UI). Manipulating DOM elements and attributes from a controller is a big no-no in AngularJS world.
You might check this answer for more info: https://stackoverflow.com/a/12431211/1418796
The angular way is shown in the angular docs :)
https://docs.angularjs.org/api/ng/directive/ngReadonly
Here is the example they use:
<body>
Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
<input type="text" ng-readonly="checked" value="I'm Angular"/>
</body>
Basically the angular way is to create a model object that will hold whether or not the input should be readonly and then set that model object accordingly. The beauty of angular is that most of the time you don't need to do any dom manipulation. You just have angular render the view they way your model is set (let angular do the dom manipulation for you and keep your code clean).
So basically in your case you would want to do something like below or check out this working example.
<button ng-click="isInput1ReadOnly = !isInput1ReadOnly">Click Me</button>
<input type="text" ng-readonly="isInput1ReadOnly" value="Angular Rules!"/>