AngularJS - ng-hide with different ng-controller - javascript

here is my problem :
When I double click in a row of an array, I want to make disappear several parts of my page. The problem is...I don't figure out how to do this.
Basically, here is my html file:
<div id="mainWindow" ng-hide="hideAlias" ng-controller="mainWindow">
...
<div id="table{{workspace.name}}" class="table" ng-controller="table" >
<table id="mainTable" class="mainTable">
<tr class="tableHeader">
<th>AA</th>
<th>BB</th>
<th>Options</th>
</tr>
<tr class="tableRows" id ="{{row}}" ng-repeat = "row in rowstable">
<td ng-dblclick="dblclick()" >{{row.AA}} </td>
<td>{{row.server}} <input type="button" ng-click="clickOnDeleteServer(row.BB)" value="X" style="float:right"/></td>
<td>
<input type="button" ng-click="clickOnView()" value="View"></input>
<input type="button" ng-click="clickOnDelete(row.AA)" value="Delete"></input>
</td>
</tr>
</table>
</div>
...
</div>
I have tried to do this, inside the controller "table" :
$scope.dblclick = function(){
mainWindow.hideAlias=!mainWindow.hideAlias
}
The value of hideAlias change from false to true when I double click, and vice-versa. However, nothing happens on the page (nothing gets hidden)
Any clue ? Thanks a lot
EDIT :
controller definition :
function table($scope, $http, $route){

the variable hideAlias doesn't exist on the mainWindow controller.
What you want to do is share data between the mainWindow controller and the table controller.
There's a few ways of doing this, I'll show you one
Sharing data between controllers via Event emmiters
At high level, controller Table will send data to Controller MainWindow, and controller Table is child of controller MainWindow, so here's how you do it with event emmiters:
Controller mainWindow:
$scope.$on('EventFromTableController',function(data){
$scope.hideAlias = data.hideAlias;
});
This will tell controller mainWindow to listen for the EventFromTableController event. That event will contain data attached. In this case it will hold the hideAlias value from the child controller.
Now at controller Table:
Controller table:
var tableHideAlias = true; // initialize it to true or false
$scope.dblclick = function(){
//change the local tableHideAlias state
tableHideAlias = !tableHideAlias;
// emit the new hideAlias value
$scope.$emit('EventFromTableController',{hideAlias: tableHideAlias});
}
so when dblclick executes, it will send the new hideAlias value to the parent controller (mainWindow).
This way, ng-hide will have a hideAlias scope variable to evaluate it's state.

You can achieve this in simple way.
In your case controller, mainWindow is the parent controller and controller, table is the child controller.
Create an object for the parent controller and access or change the value from child controller on double click event.
var app = angular.module('myapp',[]);
app.controller('mainWindow',function($scope){
$scope.parentobj = {};
$scope.parentobj.hideAlias = false;
});
app.controller('table',function($scope){
$scope.dblclicktest=function()
{
$scope.parentobj.hideAlias=true;
}
});
and use the parent object scope in html to hide Div
<div id="mainWindow" ng-hide="parentobj.hideAlias" ng-controller="mainWindow">
Here is the JSFiddle
In the JSFiddle, double click on AA will hide the div.

Related

ng-model not binding to input data within ng-repeat

Using AngularJs 1.6.7, I have created a table which pulls project details from a database and displays these details within a table. Each row has a modify/update button using ng-show/hide. When modify is clicked, the div changes to editable input fields, when update is clicked, the new input data will be update in the database.
I am trying to access input items within an ng-repeat and using ng-model to bind the input to update projects in a database using Flask.
The problem is that when I access the data in AJS once update is clicked, no data has binded to the new input values.
My HTML looks like this.
<tr data-ng-repeat="(key, value) in projects" >
<td>
<div data-ng-hide="edditable_project[value.project_name]">{[value.project_name]}
</div>
<div data-ng-show="edditable_project[value.project_name]">
<input class="form-control" data-mg-model="updatedProjectName" value="{[value.project_name]}">
</div>
</td>
<td>
<button class="btn btn-danger add-on pull-right btn-sm" data-ng-click="removeProject(value)">Delete</button>
<button class="btn btn-primary add-on btn-sm pull-right" data-ng-hide="edditable_project[value.project_name]" data-ng-click="modify(value.project_name)">Modify</button>
<button type="submit" class="btn btn-success pull-right btn-sm " data-ng-show="edditable_project[value.project_name]" data-ng-click="update(value)">Update</button>
</td>
</tr>
And my controller looks like this:
app.controller('projectSettingsController', ['$scope', '$http', function($scope, $http) {
$scope.modify = function(project) {
$scope.edditable_project[project] = true;
};
$scope.update = function(project) {
data = {
project_name: $scope.updatedProjectName,
}
console.log($scope.updatedProjectName);
// Update project.
$http.post('/api/project/update-project', data).then(function(response) {
toastr.success(response.data);
});
$http.get('/api/project/get-all-project-details').then(function (response) {
$scope.projects = response.data;
});
$scope.edditable_project[project] = false;
};
}]);
The current output for ng-model="updatedProjectName" is undefined.
Am I doing something wrong within the scope?
well you should define your binding vairable in the scope of your controller like
$scope.updatedProjectName =""; by default it`s null as you have described, but for all your inputs you will have one data binding, i think you should have some
$scope.data={};
tr data-ng-repeat="(key, value) in projects" >
<input data-ng-model="data[key]">
</tr>
and you don`t need to set value in your input, ng-model will make it for you
You are trying to access a variable which is defined inside of ng-repeat's scope. What you would want to do in this case is pass value and work on the project variable inside the update function.
Change your mark up to data-mg-model="value.project_name". Now the ng-model binds to same. When the update completes set the latest data(if needed) as properties on project. It will reflect in the view because of 2 way data binding
Inside update you should do as follows
$scope.update = function(project) {
// Update project.
$http.post('/api/project/update-project', project).then(function(response) {
toastr.success(response.data);
// If needed set new properties on the project variable
// based on the response
});
}
You seem to have a typo:
<input class="form-control" data-mg-model="updatedProjectName" value="{[value.project_name]}">
Use ng-model instead of mg-model.

The Data is printed in console, Assigned to $scope but NOT printing in HTML

Update
Problem:
Let me try to explain what I want in one or two lines, In Demo 1 where I've used Angular Datatables when I click on Edit button the data DOES NOT appear in Edit form, whereas in Demo 2 I haven't used any datatables but the data is clearly appearing in edit form, I want the data to appear in Demo1 using Datatables. The data is inside the $scope.update but for some reasons it is not appearing in HTML whereas using the same HTML It works perfectly without datatables.
Demo1: http://plnkr.co/edit/EXXbkPUHfxcZ3blzvMaz?p=preview
Demo2: http://plnkr.co/edit/QYZzmJNwWTQaIgvUkRzQ?p=preview
Background
Initially on the left hand side the Data is inserted from a form which contain one Input type and one Select (Colony Type), there are two forms Insert, Update form on the left hand side one form is for insertion and one for editing, when the insertion form is visible the edit form is hidden and vice versa, on the right hand side the list of data is displayed with the help of datatables along with Edit and Delete button, Important thing is the buttons are made inside the DataTable code and not on HTML page, now Delete and Insert works absolutely fine, but Edit !! No it doesn't.
Problem
Case 1: (When I use Datatables)
when the Edit button (CODED INSIDE DATATABLES) is clicked an ID is sent, In the Below picture the Id is consoled "47" then an $http request is made which brings the Data and printed in console. but when I try to inject the values back to Update form it doesn't work, although when I consoled $scope the values are injected into update object but not printing on HTML page.
Case 2: (When I don't Use Datatables)
If I don't use Datatables and click the Edit the button every thing works absolutely fine and the data is injected into update object and printed on HTML page.
HTML PAGE:
If DataTables are Used
<!-- IF DataTables are Used For printing the Data on Right Side-->
<div ng-controller="colony_Controller as Main_Module">
<table class="table table-striped table-bordered" align="center" datatable="" dt-options="Main_Module.dtOptions" dt-columns="Main_Module.dtColumns" class="row-border hover">
</table>
If DataTables are NOT Used
<!-- If DataTables are NOT Used for Printing the Data on Right Side -->
<table class="table table-striped table-bordered">
<thead>
<tr>
<th style="width: 323px;" aria-label="">Colony Name</th>
<th style="width: 170px;" aria-label="">Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="colony in es_colony_details" >
<td style="width: 323px;" aria-label="">{{colony.es_colony_name}}</td>
<td>
<button ng-click="EditColonyData(colony.es_colony_id)" class="btn btn-primary">
<i class="icon-edit"></i> Edit</button>
<button ng-click="DeleteColonyData(colony.es_colony_id)" class="btn btn-danger">
<i class="icon-remove icon-white"></i> Delete</button>
</td>
</tr>
</tbody>
</table>
Controller
Main_Module.controller('colony_Controller', function colony_Controller($window, $scope, $http, bootbox, $compile, DTOptionsBuilder, DTColumnBuilder, SimpleHttpRequest, DelMainRecPicRecUnlinkPic, message)
{
$scope.field = {};
$scope.update = {};
var dtInstance = {};
/********************************** FETCH DATA START *******************************/
$http.get('http://localhost:3000/api/SELECT/es_colony_type').success(function successCallback(data)
{
$scope.es_colony_type = data.es_colony_type;
//console.log(data.es_colony_type);
});
// ONLY USED WHEN Datatable are NOT
//$http.get("http://localhost:3000/api/SELECT/es_colony").success(function successCallback(data)
//{
// $scope.es_colony_details = data.es_colony;
// console.log(data.es_colony);
//});
/********************************** FETCH DATA END *********************************/
/********************************** DISPLAY DATA START *******************************/
var vm = this;
vm.dtOptions = DTOptionsBuilder
.fromFnPromise(function()
{
return $http.get('http://localhost:3000/api/SELECT/es_colony')
.then(function(response)
{
return response.data.es_colony;
});
})
.withOption('order', [0, 'desc'])
.withDisplayLength(5)
.withPaginationType('simple_numbers')
.withOption('createdRow', function(row, data, dataIndex)
{
$compile(angular.element(row).contents())($scope);
})
vm.dtColumns =
[
DTColumnBuilder.newColumn('es_colony_name').withTitle('Colony'),
DTColumnBuilder.newColumn(null).withTitle('Actions').notSortable().withOption('width', '31%')
.renderWith(function(data, type, full, meta)
{
return '<button class="btn btn-primary" ng-click="EditColonyData(' + data.es_colony_id + ');">' +
'<i class="icon-edit"></i> Edit' + '</button> ' +
'<button class="btn btn-danger" ng-click="DeleteColonyData(' + data.es_colony_id + ');">' +
'<i class="icon-remove icon-white"></i> Delete' + '</button>';
})
];
$scope.EditColonyData = function(id)
{
console.log(id);
$http.get('api/SELECTBYID/es_colony/es_colony_id/'+id)
.success(function(data)
{
console.log(data);
console.log($scope);
$scope.YesEdit = true;
$scope.update = data.es_colony[0];
// **This is where I'm injecting data Back to $scope object**
$scope.update.es_colony_type_id = data.es_colony[0].es_colony_type_id;
});
};
You are mixing up $scope and this for your controller model.
Since you are using controllerAs alias....all your data model needs to be bound to this in controller or you need to get rid of alias for controler and only use $scope
Most people would recommend using the alias and this
As was mentioned by #charlietfl in his answer, your example using dataTables is incorrectly assigning the same controller twice, once with ng-controller="colony_Controller" and once with ng-controller="colony_Controller as Main_Module. The data tables inside the second copy of the controller will not have access to the variables in the first controller.
<div ng-controller="colony_Controller">
....
<div ng-controller="colony_Controller as Main_Module">
<table align="center" datatable="" dt-options="Main_Module.dtOptions" dt-columns="Main_Module.dtColumns" class="row-border hover">
</table>
</div>
</div>
To correct this, you need to choose between using the first syntax ($scope) or the second (controller as) and ensure that all the code is using the same format.
In this modified version, dtOptions and dtColumns have been moved to $scope, and the extra controller removed:
$scope.dtOptions = DTOptionsBuilder
.fromSource('data_colony.json')
...
$scope.dtColumns = [
...
];
<div ng-controller="colony_Controller">
...
<div>
<table align="center" datatable="" dt-options="dtOptions" dt-columns="dtColumns" class="row-border hover">
</table>
</div>
</div>
http://plnkr.co/edit/GB0IIQQoEaLN0QPBSjCz?p=preview

binding to controller object in Angular

I'm new to angular, trying to bind an an element's content into the controller's Scope to be able to use it within another function:
here is the scenario am working around:
I want the content of the <span> element {{y.facetName}} in
<span ng-model="columnFacetname">{{y.facetName}}</span>
to be sent to the controller an be put in the object $scope.columnFacetname in the controller
Here is a snippet of what I'm working on:
<div ng-repeat="y in x.facetArr|limitTo: limit track by $index ">
<div class="list_items panel-body ">
<button class="ButtonforAccordion" ng-click="ListClicktnColumnFilterfunc(); onServerSideButtonItemsRequested(ListClicktnColumnFilter, myOrderBy)">
<span>{{$index+1}}</span>
<span ng-model="columnFacetname">{{y.facetName}}</span>
<span>{{y.facetValue}}</span>
</button>
</div>
</div>
angular.module('mainModule').controller('MainCtrl', function($scope, $http) {
$scope.columnFacetname = "";
$scope.ListClicktnColumnFilter = "";
$scope.ListClicktnColumnFilterfunc = function() {
$scope.ListClicktnColumnFilter = "\":\'" + $scope.columnFacetname + "\'";
};
}
the problem is that the $scope.ListClicktnColumnFilter doesn't show the $scope.columnFacetname within it, meaning that the $scope.columnFacetname is not well-binded.
In your ng-click instead of calling two different function
ng-click="ListClicktnColumnFilterfunc(); onServerSideButtonItemsRequested(ListClicktnColumnFilter, myOrderBy)"
you can declare like this
ng-click="columnFacetname = y.facetName; onServerSideButtonItemsRequested(columnFacetname , myOrderBy)"
You are trying to pass that model to another function by assigning it to ListClicktnColumnFilter in your controller
By doing in this way, you can achieve the same thing.
I have done one plunker with sample array,
http://embed.plnkr.co/YIwRLWXEOeK8NmYmT6VK/preview
Hope this helps!

Nested Controllers that use JSON array in AngularJS

I wanted to have nested controllers like this...
Controller 1 - This is the parent. It is populated from a JSON array that comes from a REST and uses ngRepeat.
Controller 2 - This is the child. It should get data from a REST call as well, but it needs to know which parent object it is under.
Here's a visual...
Parent 1
---Child 1
---Child 2
---Child 3
Parent 2
---Child 4
---Child 5
---Child 6
The children will be populated by calling a REST service and passing info about the parent.
Make sense?
Here is some HTML that I have structured...
<div ng-app="App">
<div ng-controller="spRisks">
<table width="100%" cellpadding="10" cellspacing="2" class="employee-table">
<tr ng-repeat="risk in Risks">
<td>
<table width="100%" cellpadding="10" cellspacing="2" class="employee-table">
<tr id="{{risk.Id}}RiskDesc">
<td>{{risk.Risk_x0020_Description}}</td>
</tr>
<tr id="{{risk.Id}}RiskControls">
<td>
<div ng-controller="spControls">
<table width="100%" cellpadding="10" cellspacing="2" class="employee-table">
<tr ng-repeat="control in Controls">
<td id="{{control.Id}}Control">{{control.Title}}</td>
<td>
<input type="radio" name="{{control.Id}}Answer" value="Yes">Yes
<input type="radio" name="{{control.Id}}Answer" value="No">No
</td>
<td>
<textarea id="{{control.Id}}Comment"></textarea>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
</div>
And here is some code I have working that populates the parent controller...
<script>
function getDataWithCaml(listName, caml) {
var endpoint = "https://myteamsite.sharepoint.com//_api/web/lists/GetByTitle('" + listName + "')/GetItems(query=#v1)?#v1={\"ViewXml\":\"'" + caml + "'\"}";
return jQuery.ajax({
url: endpoint,
method: "POST",
headers: {
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"Accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose"
}
});
}
var App = angular.module('App', ['ngRoute'])
App.controller('spRisks', function ($scope, $http) {
var caml = "<View><Query><Where><Eq><FieldRef Name='Owner'/><Value Type='Integer'><UserID/></Value></Eq></Where></Query></View>";
var ownerData = getDataWithCaml("Owners", caml);
ownerData.success(function (data) {
var arrayOfExpressions = [];
for (var i = 0; i < data.d.results.length; i++){
arrayOfExpressions.push(CamlBuilder.Expression().LookupMultiField("Process_x0020_Owner_x0020_Title").EqualTo(data.d.results[i].Title));
}
var newCaml = new CamlBuilder().View().Query().Where().All(arrayOfExpressions).ToString();
newCaml = newCaml.replace(/"/g, '\'');
var jsonData = getDataWithCaml("Risks", newCaml);
jsonData.success(function (jsonDataResults) {
$scope.$apply(function(){$scope.Risks = jsonDataResults.d.results;});
});
});
});
function replaceAll(string, find, replace) {
return string.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}
</script>
One very cool thing that you should learn about angular is that if a controller is on a child element underneath another controller, then it inherits the values of the parent into its scope. It does this through prototypal inheritance. This is worth reading up on, but it basically means that any changes you make to the child scope will not modify the parent scope, so you aren't going to corrupt anything (you can still call methods on the parent scope which can do corrupting for you. And I'm sure you can imagine other ways of interfering with the parent scope, but hopefully you see my point). So if you have:
<div ng-controller="Alpha">
<div ng-controller="Beta"/>
<div ng-controller="Beta"/>
<div ng-controller="Beta"/>
</div>
Then you have three instances of the "Beta" controller, and all of them have a parent scope created by the function "Alpha." So let's say you write the controller for alpha, like so:
function Alpha($scope) {
$scope.title = "Snow White and the Seven Dwarves";
$scope.dwarves = ['Sleepy','Sneezy','Dopey','Bashful',
'Grumpy','Doc','Happy'];
}
Then, in all three instances of "Beta", you gain access to that parent:
function Beta($scope) {
// This will write out "Snow White and the Seven Dwarves".
console.log($scope.title);
}
Now, Beta can always manipulate title, and within its own scope, title will change without affecting the other siblings. If it added a dwarf to the collection, though, then.. well... another dwarf would appear.
ng-repeat is an easy way to create lots of child scopes and then initialize each with a variable:
<div ng-controller="Alpha">
<div ng-repeat="dwarf in dwarves"/>
</div>
So each repeated div tag has its own child scope with the variable dwarf already set. It also has access to the title and even the dwarves collection.
Neat.
You can also attach to it another controller:
<div ng-controller="Alpha">
<div ng-controller="Beta" ng-repeat="dwarf in dwarves"/>
</div>
In which case, in addition to access to dwarf, dwarves, and title, it also runs the function Beta() in order to initialize whatever it needs to initialize.
I've attached a jsfiddle for you, so you can play around with a simple example:
https://jsfiddle.net/p6e0wr1y/
I hope this helps with your specific implementation. If you need me to address your stuff specifically, I will, but I'd like this answer to be valuable to anyone who finds themselves in a similar predicament.

ng-class directive call executed twice

Simple html:
<table class="table table-condensed">
<tr data-ng-repeat="customer in customers" data-ng-class="customerSelectedClass(customer)">
<td>
{{customer.Name}}
</td>
</tr>
</table>
In my controller - two functions to select customer and return proper class to highlight a table row:
$scope.customerSelectedClass = function (customer) {
if (customer == $scope.selectedCustomer) {
console.log('returing info for ' + customer.Name);
return "info";
}
return "";
};
$scope.selectCustomer = function (customer) {
console.log('selecting ' + customer.Name);
$scope.selectedCustomer = customer;
}
I noticed that when I click on a customer link, customerSelectedClass function executes twice. selectCustomer function on ng-click directive executes once, as it should. Angular is only included once on the page. I wonder if this is a bug in Angular or something that I am doing wrong?
Behind the scenes, angular is setting up a $watch on the function that is resolving the class name. Because angular uses dirty checking to see if there has been a change, this method will be called twice during the $digest cycle. This is ok.
I would suggest that you don't add this code the the controller though, because if you are managing many css classes, you could be adding a lot of unnecessary code. Try something like this instead:
<table class="table table-condensed">
<tr data-ng-repeat="customer in customers" data-ng-class="{'info': customer == selectedCustomer}">
<td>
{{customer.Name}}
</td>
</tr>
</table>
Then, there is no need for a controller function customerSelectedClass. This will only add the info class if the right-hand side of the : resolves to true. And there is no problem resolving the correct customer in the ng-repeat.
Hope this helps.

Categories

Resources