AngularJS: how to initiate a ng-click on load - javascript

We have a widget in ServiceNow where we have buttons that show pre-configured filters. The buttons work great onClick, but we would like the first button to be clicked and the first filter to be applied on load. Is there a way to initiate this on load? We tried using ng-init, but we couldn't get that to work.
<p><strong>Filters:</strong></p>
<button ng-if="options.show_preconfigured_filters=='true'"
class="btn btn-outline-primary pull-left m-r-sm m-b-sm"
ng-repeat="filters in data.preconfigured_filters | orderBy : 'order' track by $index"
ng-click="c.applyFilter(filters);">
<i class="glyphicon glyphicon-filter m-r-sm"></i>{
{filters.title}}
</button>
<div class="clearfix"></div>
c.applyFilter = function(filter) {
$scope.data.filter = filter.filter;
c.appendQuery($scope.data.filter);
}

One approach is to compute the ordered list in the controller:
var orderedList = $filter('orderBy')($scope.data.preconfigured_filters, 'order');
c.applyFilter(orderedList[0]);
This executes the same function that a user invokes by clicking the first item.

Related

Pipe to allow multiple filter values simultaneously - Angular

Buttons are generated using *ngFor bringing back as many different types of values available to filter by. I'm filtering on a key of 'location', therefore if there are locations of 'west' and 'england' then two buttons of 'west' and 'england' are available to filter by.
What I want to be able to do is select more than one filter. If I click 'england' all the results for 'england' come back, then if I click 'west' then 'west' comes back as well as 'england' still being "active". Currently, I can only click one filter at a time.
I think I need to assign an active class to my button then this will push an array of whats active to send to my pipe to do the filtering... ?
My filter Button
<div ngDefaultControl [(ngModel)]="filteredLocation" name="locationFilter" id="locationFilter">
<button value="All" class="m-2 btn btn-primary" type="button">All</button>
<button [class.active]="selectedIndex === i" (click)="filteredLocation = entry.location" class="m-2 btn btn-primary" type="button" *ngFor="let entry of timeLine | filterUnique; let i = index">{{entry.location}}</button>
</div>
single filter on results
<div class="timeline">
<my-timeline-entry *ngFor="let entry of timeLine | filter:filteredLocation:'location'" timeEntryHeader={{entry.year}} timeEntryContent={{entry.detail}} timeEntryPlace={{entry.place}} timeEntryLocation={{entry.location}}></my-timeline-entry>
</div>
I have created a stackBlitz of what I've got - try clicking on a filter you will see only one filter can be applied at one time. https://stackblitz.com/edit/timeline-angular-7-nve3zw
Any help here would be awesome. Thanks
There can be multiple ways to do that one would be to attach some property to determine if location is active for example isLocationActive
Then toggle this flag as per your need and to apply active class also you don't need filter pipe in that case
So your html will look like
<div class="form-group row">
<div ngDefaultControl [(ngModel)]="filteredLocation" name="locationFilter" id="locationFilter">
<button value="All" class="m-2 btn btn-primary" (click)="activeAllEntries()" type="button">All</button>
<button [class.active]="entry.isLocationActive" (click)="entry.isLocationActive = !entry.isLocationActive" class="m-2 btn btn-primary" type="button" *ngFor="let entry of timeLine | filterUnique; let i = index">{{entry.location}}</button>
</div>
</div>
<div class="timeline">
<ng-container *ngFor="let entry of timeLine">
<my-timeline-entry *ngIf="entry.isLocationActive" timeEntryHeader={{entry.year}} timeEntryContent={{entry.detail}} timeEntryPlace={{entry.place}} timeEntryLocation={{entry.location}}></my-timeline-entry>
</ng-container>
</div>
TS function
activeAllEntries() {
this.timeLine.forEach(t=> t.isLocationActive=!t.isLocationActive)
}
working Demo

AngularJS: Bind data returned from a modal to row it was clicked from

Using AngularJS here.
I am working on a UI which has a dropdown. Based on what the user selects I show 2 tabs to the user.
Each tab data is returned from a service which just returns an array of data (string).
Against each string value returned I show a button against it. When you click the button it opens a modal popup where the user can select some data.
When they close the modal I return the data back to the controller.
The normal flow of binding data to tab, opening modal and returning data from modal all works fine.
What I am not able to understand or design is how to bind the returned data against the button or row which it was clicked from
For example as below:
Tab1
String1 - Button1
String2 - Button2
String3 - Button3
If I open the modal by clicking button1, how do I find out button1 was pressed and bind back data that was returned from its modal.
Some of the relevant code as below:
<div id="params" ng-if="type.selected">
<tabset class="tabbable-line">
<tab heading="Sets" ng-if="sets" active="tab.set">
<div class="form-group m-grid-col-md-8 param" style="margin-top:5px"
ng-repeat="set in sets" >
<label class="control-label col-md-3 param-label">{{set}}
</label>
<button ng-click="openModal()" class="btn btn-info btn-sm">
Select
</button>
</div>
</tab>
<tab heading="Tables" ng-if="tables" active="tab.table">
<div class="form-group m-grid-col-md-8 param"
ng-repeat="table in tables">
<label class="control-label col-md-3 param-label">{{table}}
</label>
<button ng-click="openModal()" class="btn btn-info btn-sm">
Select
</button>
</div>
</tab>
</tabset>
</div>
Controller:
$scope.onChangeType = function (selectedValue) {
$scope.getData(selectedValue);
};
$scope.getData = function (selectedValue) {
//Commenting out the service part for now and hardcoding array
// service.getData(selectedValue).then(function (res) {
$scope.sets = ['Set1', 'Set2', 'Set3'];
$scope.tables = ['Table1', 'Table2'];
// });
};
$scope.openModal = function () {
myFactory.defineModal().then(function (response) {
//how to bind data from response
});
};
I have created a plnkr for this sample as:
http://plnkr.co/edit/vqtQsJP1dqGnRA6s?preview
--Edited--
<div class="form-group m-grid-col-md-8 param" ng-repeat="table in tables">
<label class="control-label col-md-3 param-label">{{table}}
</label>
<button ng-click="openModal(table)" class="btn btn-info btn-sm">
Select
</button>
<span>
{{table.utype}}
</span>
</div>
Pass the table object as an argument to the openModal function:
<button ng-click="openModal(table)">Select</button>
Use it in the openModal function:
$scope.openModal = function (table) {
myFactory.defineModal().then(function (result) {
table.utype = result.utype;
table.minvalue = result.minvalue;
});
};
Be sure to close the modal with the result:
$scope.ok = function () {
var result = {
utype: $scope.utype,
minvalue: $scope.minvalue,
};
$modalInstance.close(result);
};
Keep in mind that modals are considered disruptive and are despised by user.
Generally speaking, disruptions and distractions negatively affect human performance, a common finding in cognitive psychology. Many studies have shown that distraction greatly increases task time on a wide variety of tasks.
For more information, see
What research is there suggesting modal dialogs are disruptive?
While I dont get any error not but I dont get the text returned.
Be sure to furnish objects to the ng-repeat:
$scope.getData = function (selectedValue) {
//Commenting out the service part for now and hardcoding array
// service.getData(selectedValue).then(function (res) {
̶$̶s̶c̶o̶p̶e̶.̶t̶a̶b̶l̶e̶s̶ ̶=̶ ̶[̶'̶T̶a̶b̶l̶e̶1̶'̶,̶'̶T̶a̶b̶l̶e̶2̶'̶]̶;̶
$scope.tables = [
{name:'Table1',},
{name:'Table2',},
];
// });
};
The DEMO on PLNKR
Try to pass the table to openModal in your template
<button ng-click="openModal(table)"
Now you can use it as a reference in your openModal function
$scope.openModal = function (table) {
// table === the clicked table
}

How can I prevent Angular from re-sorting my list while editing?

I created a little application using Angular to manage Todolists. Each list has a number of todos. Each todo has attributes name, value1 and value2.
Each list should be sorted automatically by Angular, so I used ng-repeat="todo in selectedList.todos | orderBy: todoOrderFilter":
<ul class="list-group">
<li class="list-group-item" ng-repeat="todo in selectedList.todos | orderBy: todoOrderFilter">
<div>
<span>{{todo.name}} (Value1: {{todo.value1}}, Value2 {{todo.value2}})</span>
<button type="button" class="btn btn-warning btn-xs" ng-click="editTodo(todo)"><i class="icon-trash"></i> Edit</button>
<button type="button" class="btn btn-danger btn-xs floatright" ng-click="deleteTodo(todo)"><i class="icon-trash"></i> Delete</button>
</div>
</li>
</ul>
In my controller I defined my order filter like this:
$scope.todoOrderFilter = function (todo) {
return todo.value1 * todo.value2;
};
This works well so far until I tried to make each row editable. To accomplish this, I added an additional <div> with input elements to edit the values inside each <li> and also added ng-hide="todo.editing" and ng-show="todo.editing" to be able to turn on/off edit mode by simply setting todo.editing=true or false;
Full HTML looks like this:
<ul class="list-group">
<li class="list-group-item" ng-repeat="todo in selectedList.todos | orderBy: todoOrderFilter">
<div ng-hide="todo.editing">
<span>{{todo.name}} (Value1: {{todo.value1}}, Value2 {{todo.value2}})</span>
<button type="button" class="btn btn-warning btn-xs" ng-click="editTodo(todo)"><i class="icon-trash"></i> Edit</button>
<button type="button" class="btn btn-danger btn-xs floatright" ng-click="deleteTodo(todo)"><i class="icon-trash"></i> Delete</button>
</div>
<div ng-show="todo.editing">
<input id="todoname" ng-model="todo.name" ng-enter="updateTodo(todo)" type="text" class="form-control marginBottom" placeholder="Todo speichern" aria-describedby="basic-addon2"></input>
Value1: <input ng-model="todo.value1" ng-enter="updateTodo(todo)" type="text" class="form-control marginBottom" placeholder="Value1" aria-describedby="basic-addon2"></input>
Value2: <input ng-model="todo.value2" ng-enter="updateTodo(todo)" type="text" class="form-control marginBottom" placeholder="Value2" aria-describedby="basic-addon2"></input>
<button type="button" class="btn btn-default" ng-click="updateTodo(todo)">Save</button>
<button type="button" class="btn btn-danger" ng-click="cancelUpdateTodo(todo)">Cancel</button>
</div>
</li>
</ul>
Edit button handler:
$scope.editTodo = function(todo) {
todo.editing = true;
};
This kinda works but while I edit input fields for value1 or value2 my sort function is automatically triggered which causes the <li> elements to jump up and down which is really bad.
So what I basically want is that my auto sort filter is disabled while todo.editing=true.
So far I found these similar questions on SO but they weren't really helpful:
Disabling orderBy in AngularJS while editing the list (Don't understand how to apply the answer there to my code)
https://stackoverflow.com/questions/30845516/stop-ng-repeat-auto-sorting-your-objects-while-editing-text-box-and-checkbox-in (No answer)
Question: How can I prevent Angular from resorting the todo list while todo.editing=true?
The solution was to edit a copy of the object instead of directly editing it. Then, replace the original object with the copy when the user finished editing.
I firmly believe in utilising code that has already been written for us by the Angular team, and building upon it. As such, I think this is a perfect scenario for decorating the built-in orderBy filter to accept a fourth argument (ignore).
I haven't tested this myself very thoroughly but it should do the trick;
app.config(function ($provide) {
$provide.decorator('orderByFilter', function ($delegate) {
// Store the last ordered state.
var previousState;
return function (arr, predicate, reverse, ignore) {
// If ignore evaluates to a truthy value, return the previous state.
if (!!ignore) {
return previousState || arr;
}
// Apply the regular orderBy filter.
var order = $delegate.apply(null, arguments);
// Overwrite the previous state with the most recent order state.
previousState = order;
// Return the latest order state.
return order;
}
});
});
Usage:
<div ng-repeat="d in data | orderBy:predicate:reverse:ignore">
<!-- in your case -->
<div ng-repeat="todo in selectedList.todos | orderBy:todoOrderFilter:false:todo.editing>
I hope all of that makes sense (maybe even just works™).

How do I remove a class from another element with using angularjs and without using jquery

I'm new in angularjs , I want to add a class to a <div> when the div is clicked, and then remove the class when I click on another <div> in my html file, how can i do that? I've tried many different ways, but can't solve the problem. For example, I've tried this.
<div class="mainMenu dashboard" ng-click="itemClicked($index);" ng-class="{ 'newMainMenu': $index == selectedIndex ,'newDashboard': $index == selectedIndex }">
<div class="closeElement" ng-click="itemClicked(-1)"></div>
and in controller i use this code
scope.selectedIndex = 0;
$scope.itemClicked = function ($index) {
console.log($index);
$scope.selectedIndex = $index;
}
another way that i test
<div class="mainMenu news " ng-click="flag = 1;" ng-class="{ 'newMainMenu': flag == 1 }">
how can I remove that class without using jquery?
If you are looking to implement a navigation menu, in the HTML
<ul class="menu">
<li ng-repeat="m in menus" ng-class="{selected:m==selectedItem}" ng-click="selectedItem=m">{{m}}</li>
</ul>
and in the the scope
$scope.menus = ["Home", "Contact", "Location"]
altough you didn't show all of your code, here's a simple example you can learn from:
you need to set a variable on the controller's $scope, set it to true/false when elements are clicked, and give the proper class to each element according to that variable's value
app.controller('DataCtrl', function($scope) {
$scope.status = true;
});
and in your html:
<div ng-controller="DataCtrl">
<form>
<button type="button" ng-click="status = !status" class="btn btn-lg" ng-class="{'btn-success' : status, 'btn-danger' : !status}">
1
</button>
<button type="button" ng-click="status = !status" class="btn btn-lg" ng-class="{'btn-danger' : status, 'btn-success' : !status}">
2
</button>
</form>
</div>
I found out where is my problem repeat the name of a controller isn't make a integrated scope I can not using a value with same name in that area i must just use controller name one time and put of code in one div

Running click functions on every instance of listing instead of current

I have a listing of articles here, and I can't figure out how to execute the ng-click function calls on every new article inside the ng-repeat. Right now it works for existing articles, but when new articles are added dynamically (via AJAX), I need those to have the same functionality too.
For example: the ng-click function calls on the "+" sign to reveal social buttons seem to not work once new articles are inserted via AJAX (ie: delete articles, and let list be populated again with new elements)
Does AngularJS provide any tools to do that?
<div>
<div>
<input type="text" ng-model="search">
<span>{{filtered.length}} article(s)</span>
</div>
<div article-listing ng-repeat="article in filtered = (wikiArticles | filter:search)">
<!--Individual article begin-->
<span>
{{article.title}}
</span>
<div>
<a ng-click="articles.removeArticle($index)" title="Delete">
<span>✖</span>
</a>
<a ng-click="articles.toggleShare(article)">
<span class="plus-sign" title="Share">✖</span>
<div social-share ng-show="article.socialShare">
<div ng-click="socialShare = !socialShare" class="addthis_toolbox addthis_default_style addthis_32x32_style"
addthis:title="{{article.title}}" addthis:description="{{article.extract}}" addthis:url="{{article.url}}">
<a class="addthis_button_facebook"></a>
<a class="addthis_button_twitter"></a>
<a class="addthis_button_google_plusone_share"></a>
<a class="addthis_button_reddit"></a>
<a class="addthis_button_hackernews"></a>
</div>
</div>
</a>
</div>
<div>{{article.extract}}</div>
<!--Individual article end-->
</div>
</div>
Code for ng-click calls that don't seem to work for new article insertions
$scope.articles = (function() {
return {
shuffleArticles : function() {
$scope.wikiArticles.reverse();
},
removeArticle : function(index) {
$scope.wikiArticles.splice(index, 1);
$scope.fireAPICalls();
},
toggleShare : function(currArticle) {
var previousState = currArticle.socialShare;
angular.forEach($scope.wikiArticles, function(article) {
article.socialShare = false;
});
currArticle.socialShare = previousState ? false : true;
}
}
})();
Your ng-click calls are actually working- you can watch the ng-show toggle in the debugger.
The problem is that there is nothing to display on the new items you add.
The articles you initially add all have their icons populated with the .addthis classes, for instance here's your Facebook icon element:
<a class="addthis_button_facebook at300b" title="Facebook" href="#">
<span class=" at300bs at15nc at15t_facebook">
<span class="at_a11y">Share on facebook</span>
</span>
</a>
at300bs includes the following css which displays the image:
background: url(widget058_32x32.gif) no-repeat left!important;
However as you add new items, you aren't including the needed .addthis classes to them. Their elements look like this:
<a class="addthis_button_facebook"></a>
So ng-show has nothing to display (it shows a 0x0 div).
Add the .addthis classes to your new elements as you add them and you'll be all set.

Categories

Resources