Multiselect dropdown in Angular js with xeditable - javascript

I am using an AngularJS template in my project. In that having so many controls like textbox, dropdown, datepicker etc.. I want to change the drodown to be multiselect.
I am using xeditable.js from the below ones
http://vitalets.github.io/angular-xeditable/
https://github.com/vitalets/angular-xeditable
See part of the templated html sample below
<div ng-controller="CriteriaCtrl" ng-cloak>
<div class="well editable-criteria span12" ng-show="hasKeys()">
<div class="criteria-loading" ng-show="criterialoading"></div>
<ul ng-hide="criterialoading">
<li ng-repeat="criteriaName in criteriaNames" class="{{criteriaName}}">
<div ng-switch on="criteria[criteriaName].type">
{{criteria[criteriaName].displayLabel}}:
<span ng-switch-when="text">
<a href="#" editable-text="criteria[criteriaName].currentValue"
onbeforesave="updatetext($data, criteria[criteriaName].name)"
onshow="hideOtherPopups(criteriaName)">
{{ criteria[criteriaName].currentDisplayValue || ' ' }}
</a>
</span>
<span ng-switch-when="dropdown">
<a href="#" editable-select="criteria[criteriaName].currentValue.currentValue"
e-ng-options="p.currentValue as p.currentValueLabel for p in possible[criteriaName]"
onshow="hideOtherPopups(criteriaName)"
onbeforesave="updatedropdown($data, criteriaName)">
{{criteria[criteriaName].currentValueLabel}}
</a>
</span>
<span ng-switch-when="date">
<a href="#" editable-bsdate=" criteria[criteriaName].currentValue"
e-datepicker-popup="dd-MMMM-yyyy" onshow="makedatepicker(criteriaName)"
onbeforesave="updatedate($data, criteria[criteriaName].name)"
class="editable-date">
{{ ( criteria[criteriaName].currentValue | date:"dd/MM/yyyy") || empty }}
</a>
</span>
</div>
</li>
</ul>
</div>
</div>
Part of the xeditable for dropdown
angular.module('xeditable').directive('editableSelect', ['editableDirectiveFactory',
function (editableDirectiveFactory) {
return editableDirectiveFactory({
directiveName: 'editableSelect',
inputTpl: '<select class="xx" multiple="multiple"></select>',
autosubmit: function () {debugger
var self = this;
self.inputEl.bind('change', function () {
self.scope.$apply(function () {
self.scope.$form.$submit();
});
});
}
});
}]);
Because of project complexity, I am not able to provide entire html and script code.
I just need some idea about how I can go further for multi-select dropdown option.
I am using xeditable.js the same way as in the link provided above. Multiple attributes modify the appearance of dropdown. I want something like need to select multiple items and separated by comma.
Can anyone provide the direction for implementing multi-select dropdown in AngularJS with xeditable?

Add in your xeditable.js
angular.module('xeditable').directive('editableMultiselect', ['editableDirectiveFactory',
function (editableDirectiveFactory) {
return editableDirectiveFactory({
directiveName: 'editableMultiselect',
inputTpl: '<select size="6" multiple></select>',
autosubmit: function () {
var self = this;
self.inputEl.bind('change', function () {
self.scope.$apply(function () {
self.scope.$form.$submit();
});
});
}
});
}]);
In your Form
<span editable-multiselect="user.name" e-name="name" e-ng-options="Status.ID as Status.name for Status in Users">
{{user.name || 'Not Set'}}
</span>

Related

Disable close dropdown after click href

I would like to keep my dropdown opened after a page load. For example if I click on an item(href) into an dropdown, I would like to keep the dropdown opened after the redirection.
I've seen that there is a method jquery named stopPropagation, but it seems that this does not work for me
HTML
<div class="sidenav">
<div class="item_sn">
Groups
</div>
<div class="item_list_body">
<div class="link_sidenav">
<a href="#" class="sub_item">
group 1
</a>
</div>
<div class="link_sidenav">
<a href="#" class="sub_item">
group 2
</a>
</div>
</div>
<div class="item_sn">
Users
</div>
<div class="item_list_body">
<div class="link_sidenav">
<a href="#" class="sub_item">
user 1
</a>
</div>
<div class="link_sidenav">
<a href="#" class="sub_item">
user 2
</a>
</div>
</div>
</div>
JQuery
<script>
$(document).ready(function () {
$('.item_list_body').hide();
$('.item_sn').on('click', function (event) {
var content = $(this).next('.item_list_body')
content.slideToggle();
$('.item_list_body').not(content).slideUp();
});
});
</script>
Solution 1 (not working) :
$(document).on('click', '.sub_item', function (e) {
$(this).parent('.link_sidenav').parent('.item_list_body').toggle();
});
you can use sessionStorage to store the state of the menu and then open the menu on page load by checking the state see below
EDIT
rather than using state of the menu we should save the index of the clicked menu as discussed in the comment so updated my answer
$(document).ready(function () {
//sessionStorage.removeItem('opened');
$('.item_list_body').hide();
if (sessionStorage.getItem('opened') !== null) {
$('.sidenav>div:eq(' + sessionStorage.getItem('opened') + ')').next('.item_list_body').show();
}
$('.item_sn').on('click', function (event) {
var content = $(this).next('.item_list_body');
var elem = $(this);
content.slideDown(0, function () {
sessionStorage.setItem('opened', elem.index());
});
$('.item_list_body').not(content).slideUp();
});
});
Hope it helps

accessing angular HTML from custom controller

OK, I have a custom template I am using where i have several accordions containing lists where the user can click on the option and it becomes active. However I cannot access the parent scope in the controller to change remove the active class from the previously clicked item.
Basically what I want is when a user clicks on a list item, it becomes active and the other items become inactive.
Here is the plunker: http://plnkr.co/edit/d5kHjH?p=preview
Here is the pertinent code:
.run(function(formlyConfig) {
formlyConfig.setType({
name: 'label',
template: `<div ng-init= "active = false">
<a li class="list-group-item small" ng-click="addActive(); active = !active" ng-class="{'active': active === true}"><span class="glyphicon glyphicon-chevron-right"></span> {{to.label}}</li></a>
</div>`,
controller: function($scope) {
$scope.addActive = function() {
$(this).parent().children().removeClass("active");
$(this).addClass("active");
$scope.model.PROC = $scope.to.label;
console.log($scope.model.PROC);
};
}
});
})
I want to be able to add the inactive class to the previously created items, which are being called from an ng-repeat from here in the HTML:
<uib-accordion close-others="true">
<ul class="list-group">
<div uib-accordion-group="" class="panel-primary" ng-repeat="accordion in vm.accordions" active="accordion.active" is-open="isopen">
<uib-accordion-heading ng-click="isopen=!isopen">
<span class="label label-info pull-left">{{accordion.label}}</span>
{{accordion.title}}
</uib-accordion-heading>
<formly-form model="accordion.form.model" fields="accordion.form.fields" form="vm.form" options="accordion.form.options"></formly-form>
</div>
</ul>
</uib-accordion>
The formly-form line is where the template item are being added in on by one

Create custom follow button for my application

I would like a directive that dynamically knows if I'm following the user in my App.
I have a resource to get the currentUser
this.following = function () {
var defer = $q.defer();
var user = $cookies.getObject('currentUser');
UserResource.get({id: user.id}).$promise.then(
function (data) {
defer.resolve(data.following);
});
return defer.promise;
};
This is in one of my services. It returns all users that I'm following.
When instantiating my controller I fetch the users I follow within my app:
UserService.following().then(
function (data) {
$scope.following = data;
});
I would like to move that into a directive so that I can easily reuse it somewhere else in my app.
This is the HTML I am using right now (and it's not really beautiful) :
<div class="item" ng-repeat="user in users">
<div class="right floated content">
<div ng-show="isFollowing(user)" class="ui animated flip button" tabindex="0"
ng-click='unFollow(user)'>
<div class='visible content'>
Following
</div>
<div class="hidden content">
Unfollow
</div>
</div>
<div ng-hide="isFollowing(user)" ng-click="follow(user)" class="ui button">Follow</div>
</div>
</div>
But instead something like :
<div class="item" ng-repeat="user in users">
<um-follow-button um-user="user"></um-follow-button>
</div>
then depending if I'm following the user or not then render one of the two options.
I don't know if I will have to use a controller in my directive.
I have looked at : https://gist.github.com/jhdavids8/6265398
But it looks like a mess.

Click button to copy text to another div with angularjs

I have a list of Items with different button with them. Plunker
Quick View:
I want something like if I click on any of the buttons, related text will be copy to the div above. Also if I click on the button again it will removed from the Div.Same for each of the buttons. [I added manually one to show how it may display ]
I am not sure how to do that in Angular. Any help will be my life saver.
<div ng-repeat="item in csTagGrp">
<ul>
<li ng-repeat="value in item.csTags">
<div class="pull-left">
<button type="button" ng-class='{active: value.active && !value.old}' class="btn btn-default btn-xs">{{value.keys}}</button>
<span>=</span>
</div>
<div class="pull-left cs-tag-item-list">
<span>{{value.tags}}</span>
</div>
</li>
</ul>
</div>
The simplest thing would be to use $scope.tags object to store selected tags and add/remove them with the scope method similar to this:
$scope.tags = {};
$scope.toggleTag = function(tag) {
if (!$scope.tags[tag]) {
$scope.tags[tag] = true;
}
else {
delete $scope.tags[tag];
}
};
Demo: http://plnkr.co/edit/FrifyCrl0yP0T8l8XO4K?p=info
You can use ng-click to put in your scope the selected value, and then display this value instead of "Win".
http://plnkr.co/edit/IzwZFtRBfSiEcHGicc9l?p=preview
<div class="myboard">
<span>{{selected.tags}}</span>
</div>
...
<button type="button" ng-click="select(value)">{{value.keys}}</button>

AngularJS ngRepeat element removal

There are quite a few questions on how to implement item removal inside ngRepeat directive, and as I figured out, it comes down to using ngClick and triggering some remove function passing it item's $index.
However, I couldn't find anywhere an example where I have multiple ngRepeats:
<div ng-controller="MyController">
<div ng-repeat="email in user.emails">
{{ email }} <a href>Remove</a>
</div>
<div ng-repeat="phone in user.phones">
{{ phone }} <a href>Remove</a>
</div>
</div>
For this, I would need to create $scope.removePhone and $scope.removeEmail which would be called using ngClick on Remove anchor. But I'm looking for a more generic solution. Especially since I have many pages with many ngRepeats .
I was thinking about writing a directive which would be placed on Remove anchor and would do something like this:
Find ngRepeat among parent elements.
Read what it's iterating over ('user.emails' in first case, 'user.phones' in second)
Remove $index element from THAT model.
So the markup would look something like this:
<div ng-controller="MyController">
<div ng-repeat="email in user.emails">
{{ email }} <a href remove-directive="$index">Remove</a>
</div>
<div ng-repeat="phone in user.phones">
{{ phone }} <a href remove-directive="$index">Remove</a>
</div>
</div>
Is what I'm looking for possible to achieve and what would be the preferred way to do this?
Current hacky solution
Here is how I do it currently. It's hacky and ugly but gets the job done until I figure out a prettier way.
myAppModule.controller('MyController', function ($scope, $parse, $routeParams, User) {
$scope.user = User.get({id: $routeParams.id});
$scope.remove = function ($index, $event) {
// TODO: Find a way to make a directive that does this. This is ugly. And probably very wrong.
var repeatExpr = $($event.currentTarget).closest('[ng-repeat]').attr('ng-repeat');
var modelPath = $parse(repeatExpr.split('in')[1].replace(/^\s+|\s+$/g, ''));
$scope.$eval(modelPath).splice($index, 1);
};
});
And in DOM:
<div ng-repeat="email in user.email" class="control-group">
<label class="control-label">
{{ "Email Address"|_trans }}
</label>
<div class="controls">
<input type="text" ng-model="email.address">
<span class="help-inline"><a href ng-click="remove($index, $event)">{{ "Delete"|_trans }}</a></span>
</div>
</div>
You could create a generic remove method that would take in the array and the item to remove.
<div ng-app="" ng-controller="MyController">
<div ng-repeat="email in emails">{{ email }} <a ng-click="remove(emails, $index)">Remove</a>
</div>
<div ng-repeat="phone in phones">{{ phone }} <a ng-click="remove(phones, $index)">Remove</a>
</div>
</div>
$scope.remove = function(array, index){
array.splice(index, 1);
}
No JS
<div ng-repeat="option in options" ng-init=options=[1,2,3,4,5]>
<button ng-click="options.splice($index,1)">Remove me</button>
</div>
<div ng-app="" ng-controller="MyController">
<div ng-repeat="email in emails as datasource">{{ email }}
<a ng-click="datasource.splice($index,1)">Remove</a>
</div>
<div ng-repeat="phone in phones as datasource">{{ phone }}
<a ng-click="datasource.splice($index,1)">Remove</a>
</div>
</div>
A very simple and convenient way that works cross-browser is to use the 'remove' utility method from the library lodash.
<div ng-repeat="phone in phones">{{ phone }}
<a ng-click="removeItem(phones, phone)">Remove</a>
</div>
In your controller you declare then
//inject lodash dependency
//declare method in scope
$scope.removeItem = function(list, item){
lodash.remove(list,function(someItem) { return item === someItem});
}
You may of course use indexes if you like. See https://lodash.com/docs#remove
If you have used ng-repeat on an object instead of an array, do the following.
<div ng-app="" ng-controller="MyController">
<div ng-repeat="email in emails">{{ email }}
<a ng-click="remove(emails, email)">Remove</a>
</div>
<div ng-repeat="phone in phones">{{ phone }}
<a ng-click="remove(phones, phone)">Remove</a>
</div>
</div>
$scope.remove = function(objects, o){
delete object[o.id];
}
or the more terse
<div ng-app="" ng-controller="MyController">
<div ng-repeat="email in emails">{{ email }}
<a ng-click="delete emails[email.id]">Remove</a>
</div>
<div ng-repeat="phone in phones">{{ phone }}
<a ng-click="delete phones[phone.id]">Remove</a>
</div>
</div>
presumes that the objects look like this
var emails = { '123' : { id : '123', .... } };
var phones = { '123' : { id : '123', .... } };

Categories