xeditable Grid's drop down values cannot change from the outside dropdown - javascript

I'm using xeditable angular directive.I need to set the grid's all the drop down values of Status column according to the value of the outside drop down.
I have set up the JsFiddle here.But it's not working.Could you tell me Why ? Thanks in advance.
Update: When I click the cancel button then it's updated.Very strange :( Could you tell me how to sort out this issue ?
HTML
<span editable-select="bulkPaymentType" e-form="tableform" e-ng-options="s.value as s.text for s in statuses" e-ng-change="setBulkPaymentType($data)">
</span>
js
$scope.setBulkPaymentType = function (data) {
for (var i = $scope.users.length; i--;) {
var user = $scope.users[i];
user.status = data;
};
};
JSFiddle

I have found the solution.Here it is :)
HTML
<span editable-select="bulkPaymentType" e-form="tableform" e-ng-options="s.value as s.text for s in statuses" e-ng-change="setBulkPaymentType($data,tableform)">
</span>
JS
$scope.setBulkPaymentType = function (data,tableform) {
for (var i = 0; i < tableform.$editables.length; i++) {
if (tableform.$editables[i].name === 'user.status') {
tableform.$editables[i].scope.$data = data;
}
}
};
Play with it : JSFiddle

Your setBulkPaymentType method is updating the users in your controller scope.
But the value in the editable input is actually a copy from your controller scope. So when you call setBulkPaymentType, you don't see them change. And when you hit cancel button, the form will display with the value in your controller scope which you updated with setBulkPaymentType, that is the reason. I don't think you can modify the $data within each editable directly since they are using isolated scope. There is no way to get access to $data from outside.

Related

AngularJS: Add inline custom code using a directive

Here's the scenario.
In the app, you can add inline custom code (HTML attributes ex. style="", onclick="alert('Test')") in an element (ex. input texts, divs). The custom code is binded to the main model and loaded to the element using a custom directive I've created. I'm doing this to control dynamically generated fields that I want to hide and show based on different inputs.
This is my custom directive that loads inline attributes on the element:
app.directive('addCustomHtml', function() {
return {
scope: {
customHtml: "="
},
link: function(scope, element, attributes){
scope.$watch('customHtml', function(newVal, oldVal) {
if (newVal) {
var attrs = newVal.split('\n');
for (var i = 0; i < attrs.length; i++) {
var result = attrs[i].split('=');
var attr = result.splice(0,1);
attr.push(result.join('='));
if (attr[1]) {
element.attr(attr[0], attr[1].replace(/^"(.*)"$/, '$1'));
}
}
} else {
if (oldVal) {
var attrs = oldVal.split('\n');
for (var i = 0; i < attrs.length; i++) {
var attr = attrs[i].split('=');
if (attr[0]) {
element.removeAttr(attr[0]);
}
}
}
}
})
}
}
});
It is binded to the element like this:
<input type="checkbox" add-custom-html custom-html="checkbox1.customHtml">Yes
To see it in action, you can check the plunkr here: https://plnkr.co/edit/xjjMRPY3aE8IVLIeRZMp?p=preview
Now my problem is, when I try to add AngularJS directives (ex. ng-show, ng-if) using my custom directive, AngularJS doesn't seem to recognize them and the model scope I'm passing inside.
Another problem is when I try to add vanilla Javascript event functions (ex. onclick="", onchange=""), it does work but sometimes AngularJS does not read them especially when the element has an ng-change, ng-click attributes.
Again, I am doing this approach on the app because I have generic fields and I want to control some of them by adding this so called "custom codes".
Any help would be highly appreciated!!
If you want to add HTML code and compile it within current $scope, you should use the $compile service:
let someVar = $compile(yourHTML)($scope);
// you can now append someVar to any element and
// angular specific markup will work as expected
Being a service, you'll need to inject it into current controller (or pre/post link function) to be able to use it.

the $watch - method isnt changing the scope-variable

In my controller I have a $scope.var=[]
when i click a button, this array gets filled with content.
so the $scope.var.length is changing from 0 to 1 for example.
When the array gets filled I want to show a div, so it has a
ng-if="condition".
This condition is saved in the controller as well:
$scope.controller = false.
Now I want that condition to be changed, when the array get filled:
$scope.$watch('var.length', function(){$scope.condition = true;});
Now (important!), there is a second option to show the div: a button with
ng-click="condition = !condition"
In the test, the ng-click is working perfectly, and the condition is changing between true and false, but when i fill the var = [] with content, the $watch-method isn´t working.
Thanks for help and tipps :)
//EDIT
html:
<div class="row">
<div ng-click="condition= !condition">
<span class="glyphicon clickable" ng-class="{'glyphicon-down': !condition, 'glyphicon-up': condition}" ></span>
</div>
<div class="slideToggle" ng-if="condition">
Text hier
</div>
</div>
You can just watch var itself instead of var.length
Check this out for an example : http://jsfiddle.net/Lzgts/577/
The code -
$scope.$watch('var', function(newVal, oldVal){
console.log(newVal);
if(newVal.length > 0 ){
$scope.condition = true;
}else{
$scope.condition = false;
}
});
This should do the trick for you.
Alternatively, you can watch var.length but you still need some if/else logic inside to check if the newVal is actually 0 or not. Something like this :
$scope.$watch('var.length', function(newVal, oldVal){
if(newVal === 0){
$scope.condition = false;
} else {
$scope.condition = true;
}
});
Such a code may lead to several problems.
You can inspect my code:
plnkr
$scope.$watch('var.length', function(newE) {
if (newE > 0) {
$scope.condition = true;
}
});
The way your var changing your array, if they are equal you have to reinitialize it. Not a very smart idea but in other way you must ensure that you array filling creates new array and angular could see that.
to give it a possibility to change a scope you have to use $timeout in my case, so be care to not get trapped in $apply loop.
Okay I did it:
change the ng-click="condition = !condition"
to ng-click="reverse()"
and in the controller you define the function:
$scope.reverse= function(){
$scope.condition= !$scope.condition;
};
Then the condition is changing as well, because it´s in the same scope now.

AngularJS typeahead otions not up to date

I'm writing a directive wrapper around a typeahead input. This directive listens for changes on a link and get's new data + options for the typeahead.
I can simply simulate this behaviour with a $timeout and demonstrated it in this plnkr.co.
JS
app.controller('sample', function($scope, $timeout) {
$scope.options = ['1800', '1900', '2100'];
// Simulate some latency
$timeout(function () {
$scope.options.push('1850');
}, 4000);
});
HTML
<div>
<input type="text" ng-model="optionValue" typeahead="opt for opt in options | filter:$viewValue">
</div>
If you start typing '18' in the input field it shows 1800 as expected. But when 1850 get's added after an amount of time, the selectable options from typeahead are not being updated.
-- FYI my real live directive looks like this --
$scope.$watch($interpolate(url), function (newUrl) {
$http.get(newUrl).then(function (response) {
$scope.options = response;
});
});
I tried to use typeahead="opt for opt in getData()" but this doesn't work because the interpolated value is not yet up to date. It's always one value behind.
Seems like an issue to post on AngularUI Bootstrap website. Matches are getting selected on every keystroke but they don't get updated if you change the underlying data between keystrokes. I don't see any work-around for this, except maybe triggering the appropriate key event handler on the input manually (when you change the collection).
If someone interested in the solution, here is how I solved it at the moment. I'm not happy with the end result, please provide me some feedback :-).
Plunkr
Check out updated-bootstrap.js, I had to add the following in order to make it work:
A custom attribute that'll be use for the $watchCollection
var customOptions = attrs.typeaheadCustomOptions || '';
In the function where it gets the matches I've added a watch if customOptions is provided:
if (customOptions) {
originalScope.$watchCollection(customOptions, function (matches) {
resetMatches();
updateMatches(matches);
});
}
And that was basically it :-), the updateMatches is just an abstraction of existing code. It's not being used by me and the manual update.
var updateMatches = function(matches) {
for (var i = 0; i < matches.length; i++) {
locals[parserResult.itemName] = matches[i];
scope.matches.push({
id: getMatchId(i),
label: parserResult.viewMapper(scope, locals),
model: matches[i]
});
}
scope.query = modelCtrl.$viewValue;
};
Opened issue on github

What is the most direct way to determine that the inner element should be displayed in AngularJS?

I have a JSON structure which represents as hierarchical elements.
It looks like the following:
{
"url":"http://docsetups.json",
"partnerId":1,
"fieldDefs":
[
{"roleName":"Make","roleId":1,
"children":[{"roleName":"Invoice Number","roleId":11}]
},
{"roleName":"Model","roleId":2,
"children":[
{"roleName":"Manufacturer","roleId":21},
{"roleName":"EquipmentCode","roleId":22},
{"roleName":"EquipmentSSN","roleId":23}
]
}
]
}
Plunker
I've have created a plunker at: http://plnkr.co/edit/betBR2xLmcmuQR1dznUK?p=preview
I am using ng-repeat to display this in elements as a hierarchy of elements like the following:
When I click on either element the entire structure expands and looks like the following:
The code which renders the DOM is nice and easy and looks like the following:
<div class="headerItem"
ng-class="{focus: hover}"
ng-mouseenter="hover = true"
ng-mouseleave="hover = false"
data-ng-click="vm.onClick(item.roleName)"
data-ng-repeat="item in vm.documentSetups.fieldDefs">{{item.roleName}}
<div class="subItem" ng-show="vm.isVisible"
data-ng-repeat="subItem in item.children">[ ] {{subItem.roleName}}
</div>
</div>
vm.isVisible
The thing to focus on here is the subitem which has the ng-show="vm.isVisible" so that it only displays if that value is true.
Show Only The Subitem of the Clicked Parent
However, I'd like to only display the subitem when its parent item is clicked -- instead of showing all subitems like it does now. Can someone offer a good way to do this? I'm hoping to do it without a directive, because I am interested in whether or not this is possible without a directive or if the code is terribly convoluted in that case.
If you have a solution which includes creating a directive, please keep it as simple as possible. Thanks.
I think you should define a flag for every item which determine if the item is open.
Then you pass the item itself into handler:
data-ng-click="vm.onClick(item)
after that - you simply need to invert isOpen flag:
function onClick(item)
{
item.isOpen = !item.isOpen;
}
The whole view snippet:
<div class="headerItem"
ng-class="{focus: hover}"
ng-mouseenter="hover = true"
ng-mouseleave="hover = false"
data-ng-click="vm.onClick(item)" data-ng-repeat="item in vm.documentSetups.fieldDefs">{{item.roleName}}
<div class="subItem" ng-show="item.isOpen" data-ng-repeat="subItem in item.children">[ ] {{subItem.roleName}}</div>
</div>
The plunker: http://plnkr.co/edit/N8mUZaVfmLpnlW4kxzSr?p=preview
#Oleksii You're answer is very close and it did inspire me to develop the following answer so I appreciate your input and I did upvote you. However, there's a bit more to it than what you gave me.
View Solution at Plunker
I forked the previous plunker and you can see the final solution at:
http://plnkr.co/edit/QvyHlLh83bEyvlNkskYJ?p=preview
No Directive Required
Now I can click either or both element and they expand independently. Here's the sample output:
It took a bit of thinking, but what I did first was create a new type which holds a roleName (consider it unique) and a isVisible boolean. I call that type visibleItem and it looks like this:
var visibleItem = function (roleName){
this.isVisible = false;
this.roleName = roleName;
};
After that I created an array to hold all the visibleItems (1 for each node):
var visibleItems = [];
Now when I load the json I go ahead and create 1 visibleItem object for each node and push it into the visibleItems array.
$http.get('items.json')
.success(function(data, status, header, config) {
vm.documentSetups=data;
for (var x = 0; x < vm.documentSetups.fieldDefs.length; x++)
{
visibleItems.push(new visibleItem(vm.documentSetups.fieldDefs[x].roleName));
}
})
They are "keyed" by their roleName (consider it unique).
Next, I had to write two helper methods (setVisibleItem and getVisibleItem)
function setVisibleItem(roleName)
{
for (var x = 0; x < visibleItems.length;x++)
{
if (visibleItems[x].roleName == roleName)
{
visibleItems[x].isVisible = !visibleItems[x].isVisible;
}
}
}
function getVisibleItem(roleName)
{
for (var x = 0; x < visibleItems.length;x++)
{
if (visibleItems[x].roleName == roleName)
{
return visibleItems[x].isVisible;
}
}
return false;
}
Wire Up The Helper Methods
Finally, I wire up the setVisibleItem to the ng-click of the element and I wire up the getVisibleItem to the ng-show directive.
data-ng-click="vm.onClick(item.roleName)"
data-ng-repeat="item in vm.documentSetups.fieldDefs">{{item.roleName}}
<div class="subItem" ng-show="vm.getVisibleItem(item.roleName)"
data-ng-repeat="subItem in item.children">[ ] {{subItem.roleName}}</div>
</div>
Summary Of How It Works
Basically each of those just iterates through the list and checks to insure if the roleName sent in matches the roleName of the item. If it does it sets or gets the value.
Solved Without a Directive and Not Bad
It's a lot more work than you think it'll be, but I didn't have to implement a directive and the code is still fairly basic.

AngularJS disabling one dropdown in ng-repeat

I have the following ng-repeat in my HTML code:
<div ng-repeat="a in items">
<div>
<span>{{a.name}}</span>
</div>
<div>
<select ng-model="a.c_id" ng-options="d.c_id as d.description for d in loclist" ng-disabled="display" ng-change="selected(a.c_id)">
</select>
</div>
Then in my controller I have:
$scope.display = false;
$scope.selected = function (value) {
$scope.te = value;
if ($scope.te == 3) {
$scope.display = true;
}
};
Problem I am facing is that when I change the selection in the drop down it is supposed to disable or enable the dropdown based on value. However when I change the selection in one of the drop down that has value of 3 all the dropdowns change to disabled state rather than that particular one.
Please let me know how to fix this code so when after ng-repeat has displayed all rows and I change the dropdown value of one of the rows it just disables that particular one rather than disabling all the dropdowns in all rows.
Angular ng-repeat creates child scopes inherited from parent scope. In your case, all your ng-repeat's scopes inherit the display property from parent scope. Therefore when this property changes, it reflects on all scopes.
Try this instead of $scope to access the current scope of ng-repeat:
$scope.selected = function (value) {
this.te = value;
if (this.te == 3) {
this.display = true;
}
};

Categories

Resources