I'm having a problem submitting my list of items from my select, I'm starting with angular and still a little lost. This is my first post here!
In my HTML I use ng-repeat to list all items, and when my screen loads my first and only item is: {{list.name}}, when I click on this item {{list.name}}, ai loads the List correctly.
<select data-placeholder="Escolha uma Empresa/Filial" multiple chosen
style="width: 100%;"
ng-model="filtroRequisicao.codigoSistemaUsuariosFiliais"
required>
<option ng-repeat="list in lista" ng-value="list.id">
{{list.name}}
</option>
</select>
Angularjs:
$scope.lista = [{}];
//Carrega as Filiais dos Cooperados
$scope.loadFiliais = function () {
var usuario = localStorage.getItem("usuarioAutenticado");
var objetoUsuario = {};
objetoUsuario = JSON.parse(usuario);
$http({
method: 'PUT',
url: '/getFiliais',
data: objetoUsuario
}).then(function (response) {
$scope.lista = response.data;
console.log($scope.lista);
},
function (response) {
console.log(response.data);
$scope.showNoty('Nenhum dado encontrado.', 'information');
});
};
$scope.loadFiliais();
One thing I realized was starting my list off of a method PUT call from angular.
$scope.lista =
[
{
'id': 1,
'name': 'American Black Bear',
},
{
'id': 2,
'name': 'Asiatic Black Bear',
},
{
'id': 3,
'name': 'Brown Bear',
},
{
'id': 4,
'name': 'Giant Panda',
},
{
'id': 5,
'name': 'Sloth Bear',
},
{
'id': 6,
'name': 'Sun Bear',
},
{
'id': 7,
'name': 'Polar Bear',
},
{
'id': 8,
'name': 'Spectacled Bear',
}
];
When I fill values out of a function, as an example, my select shows all items. Now if I populate the values inside the return from my angular PUT (response.data), my select gets no items.
It seems to me that the html is being loaded before I even finish loading all my controller in the angle.
I do not know if I'm looking the wrong way, but it seems to me a problem and I do not know how to solve
UPDATE
CSS
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
index.html:
<link rel="stylesheet" href="./vendor/angular/angular-csp.css"/>
form:
<div class="panel-body">
<p class="lt-label-required">Situação</p>
<select data-placeholder="Escolha uma Empresa/Filial" multiple class="chosen ng-cloak" chosen style="width: 100%;"
ng-model="filtroRequisicao.codigoSistemaUsuariosFiliais"
required>
<option ng-repeat="list in lista" value="{{list.id}}">
{{list.name}}
</option>
</select>
</div>
angular:
$scope.loadFiliais= function () {
$http({
method: 'PUT',
url: '/getFiliais'
}).then(function (response) {
$scope.lista = response.data;
console.log($scope.lista);
},
function (response) {
console.log(response.data);
$scope.showNoty('Nenhum dado encontrado.', 'information');
});
};
$scope.loadFiliais();
UPDATE SOLUTION
I was able to solve my problem, but I would like your help to know if this is the correct way:
I used ng-if so that when my $scope.lista is null-dir, ng-if will remove and re-create the elemento.
https://docs.angularjs.org/api/ng/directive/ngIf
Angular:
$scope.lista = [];
Html:
<select data-placeholder="Escolha uma Empresa/Filial" multiple chosen
style="width: 100%;"
ng-if="lista.length > 0"
ng-model="filtroRequisicao.codigoSistemaUsuariosFiliais"
required>
<option ng-repeat="list in lista" ng-value="list.id">
{{list.name}}
</option>
</select>
Edit:
Putting ng-cloak to the body or to the tag takes care of the {{list.name}} issue.
Making $scope.lista = [] and using ng-if inside the select with
ng-if="lista.length > 0"
solves the issue of rendering the select options.
Put an ng-cloak to the body or to the tag.
Read about it here : https://docs.angularjs.org/api/ng/directive/ngCloak.
This will take care of the {{list.name}} issue.
Make $scope.lista = [] not [{}];
An ngIf function can change a preview of your HTML and have ruins consequences in cases of a doubtful or complex upload.
For quick searches like your case, a function has a very valid job.
Related
I'm new to AngularJS and am struggling with something that should be easy.
I have this ugly looking page:
Users add new beers on this screen and a beer may have more than one style - so the 'Add' button creates a new 'Style' combo box and the 'Remove' on the left side, well, removes it.
Problem is when the user selects one style from the list it doesn't appear as selected in the combo box - ie, the style field will be empty after the dropdown list has been collapsed/closed again.
So here is my code:
Beer View
<div class="form-group" ng-repeat="style in beer.styles">
<label for="style" class="col-sm-1 control-label" ng-if="$index == 0" >Style</label>
<div class="col-sm-1" ng-if="$index > 0">
<button type="button" class="btn btn-danger" ng-click="removeStyle($index)">Remove</button>
</div>
<div class="col-sm-10">
<select class="form-control"
ng-controller="styleCtrl"
ng-model="selectedStyleId"
ng-options="style.id as style.name for style in styles"
ng-change="updateStyle($index, selectedStyleId)">
</select>
</div>
<div class="col-sm-1">
<button type="button" class="btn btn-primary" ng-click="addNewStyle()">Add</button>
</div>
</div>
Style Controller (Dummy Impl)
.controller('styleCtrl', ["$scope", "$location", function ($scope, $location) {
$scope.styles = [
{ 'id': '1',
'name': 'Lager' },
{ 'id': '2',
'name': 'American Blonde Ale' },
{ 'id': '3',
'name': 'American Stout' },
{ 'id': '4',
'name': 'Cream Ale' },
{ 'id': '5',
'name': 'Bock' },
{ 'id': '6',
'name': 'German Pilsener' }
];
}]);
Beer Controller
.controller('beerCtrl', ["$scope", "$location", function ($scope, $location) {
$scope.beer = {
'styles': [
{ 'id' : '-1' }
]
}
$scope.addNewStyle = function() {
$scope.beer.styles.push({ 'id': '-1' });
}
$scope.removeStyle = function(index) {
$scope.beer.styles.splice(index, 1);
}
$scope.updateStyle = function(index, styleId) {
$scope.beer.styles[index] = { 'id': styleId };
}
The styleId is correctly set in the array, the only problem really is in the screen.
Have you spotted anything wrong in my code?
P.S.: I suspect the fact I have two controllers - the BeerController and a 'nested' StyleController in the same view may be related to the root cause.
As I mentioned I'm brand new to AngularJS so my mistake was rather simple. Instead of using on-change, I've binded the selected value to the backing object directly:
<select class="form-control"
ng-controller="styleCtrl"
ng-model="beer.styles[$index].id"
ng-options="style.id as style.name for style in styles">
That got the job done. Silly oversight.
I cant make my model to be updated when I select an option.
Here is my view:
<select data-ng-model="period" ng-options="item.value as item.text for item in periodOptions"></select>
And in my controller.js I have the following :
$scope.periodOptions = [
{ text: "This week", value: 'week' },
{ text:"This month", value: 'month '},
{ text:"This year", value: 'year' },
{ text:"All times", value: 'all-time '}
];
$scope.Search = function () {
return $http({
url: '/api/get',
method: 'GET',
params: {
period: $scope.period
}
}).then(function(response) {
console.log(response);
}, function(reason) {
alert(reason);
});
};
The $scope.period does not take the value of the option that is chosen from the User. I spent many hours on this and can't figure it out why is this happening.
In my case ng-model was not updating because my select is inside an element with ng-if.
<div class="editor-panel" ng-if="editorEnabled">
...
<select ng-options="item as item.description for item in items" ng-model="selectedItem"/>
...
</div>
ng-if creates another scope and ng-model refers to a variable in this child scope rather than the intended variable.
To fix the issue I changed ng-model="selectedItem" value to ng-model="$parent.selectedItem
There is a note in angularjs documentation for select.
"Note: ngModel compares by reference, not value. This is important when binding to an array of objects. See an example in this jsfiddle. "
Here is the fiddle of same solution as yours.
Below is a solution which should work (Notice a minor change to your existing code use ng-options="item as item.text ... instead of ng-options="item.value as item.text). Hope this helps!
var myCtrl = function($scope){
$scope.periodOptions = [
{ text: "This week", value: 'week' },
{ text:"This month", value: 'month '},
{ text:"This year", value: 'year' },
{ text:"All times", value: 'all-time '}
];
$scope.Search = function () {
alert('will call api with period: '+$scope.period.text);
/*
return $http({
url: '/api/get',
method: 'GET',
params: {
period: $scope.period
}
}).then(function(response) {
console.log(response);
}, function(reason) {
alert(reason);
});
*/
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="myCtrl">
<select data-ng-model="period" ng-options="item as item.text for item in periodOptions" ng-change="updatePeriod()"></select>
<div>{{period}} </div>
<button ng-click='Search()' >Search</button>
</div>
try this
<div ng-controller="MyCtrl">
<select data-ng-model="period" ng-options="item.value as item.text for item in periodOptions"></select>
<span>period value=, {{period}}!</span>
</div>
The code for select and ngOptions is correct. However I assume that you want $scope.Search function to be called on every option change. In this case you need to set up ngChange handler:
<select ng-model="period"
ng-options="item.value as item.text for item in periodOptions"
ng-change="Search()">
</select>
I have created a multiselect select box using Angular JS: below is the code for the same:
JS:
$scope.foobars = [{
'foobar_id': 'foobar01',
'name': 'foobar01',
}, {
'foobar_id': 'foobar02',
'name': 'foobar02',
}, {
'foobar_id': 'foobar03',
'name': 'foobar03',
}, {
'foobar_id': 'foobar04',
'name': 'foobar04',
}, {
'foobar_id': 'foobar05',
'name': 'foobar05',
}];
HTML:
<select multiple="multiple" size="5" id="selFooBar" ng-model="foobarName" ng-options="medcenter as medcenter.name for medcenter in medcenters track by medcenter.medcenter_id">
<option selected="selected">Select All</option>
</select>
And the output is :
Question 1: Why am I not getting the default option "Select All" in the list? And How do I get that?
Question 2: How can I Select All optiions on click of "First Option : Select All"??
Please suggest!
If you want to keep the <option> in the <select> element before you add the ng-options you'll have to use transclusion. the ng-options directive doesn't use transclusion, but you can create a custom directive that does. You can do that by utilizing transcludeFn in the directive post compile function:
compile: function(element,attrs) {
return {
post: function(scope, element, attributes, controller, transcludeFn){
transcludeFn(function(clone, scope) {
// prepend the transcluded content to the select
element.prepend(clone);
// set the onclick of the clone to call the selectAll function
clone.bind('click', function(){
clone.scope().$parent.selectAll();
scope.$apply();
})
});
}
}
},
controller: function($scope) {
$scope.selectAll = function() {
$scope.selectedValues = $scope.values;
}
}
Then you can set the selectedValues to all possible values on the scope, whether that's isolate or inherited. In the following plnkr example it's isolated. On click the Select All option will select the other elements.
Plunker Example
SITUATION:
I am making an app in AngularJs that assign permissions.
In order to do this i have three nested ng-repeat.
First loop: display PERMISSION GROUP
Second loop: For each permission group display CATEGORIES.
Inside this loop execute a function that will get all the SUB CATEGORIES for each category
Third loop: display SUB CATEGORIES
ISSUE:
The problem is in the execution of the function inside the second loop.
ATTEMPT 1 - ng-init:
<div class="row" ng-repeat="permission_group in list_permission_groups">
<div class="col-sm-3">
<h3>
{{permission_group.permission_group_name}}
</h3>
</div>
<div class="col-sm-9">
<ul>
<li ng-repeat="category in list_categories">
<span>
{{ category.name }}
</span>
<div class="checkbox">
<label>
<div ng-init="temp_result = get_Sub_Categories(category.category_id)">
<p ng-repeat="sub_category in temp_result">
{{ sub_category.name }}
</p>
</div>
</label>
</div>
</li>
</ul>
</div>
</div>
In the controller:
$scope.get_Sub_Categories = function(category_id) {
$http({
url: base_url + 'main/json_get_list_sub_categories',
data: {
category_id: category_id
},
method: "POST"
}).success(function(data) {
return data;
});
}
Te behavior is quite strange. Porbably due to dirty checking the page is loaded 682 times.
No result is displayed.
ATTEMPT 2 - ng-click: (only for debug)
<div class="row" ng-repeat="permission_group in list_permission_groups">
<div class="col-sm-3">
<h3>
{{permission_group.permission_group_name}}
</h3>
</div>
<div class="col-sm-9">
<ul>
<li ng-repeat="category in list_categories">
<span>
{{ category.name }}
</span>
<div class="checkbox">
<label>
<button ng-click="get_Sub_Categories(category.category_id)">
GET SUB-CATEGORIES
</button>
{{ list_sub_categories }}
</label>
</div>
</li>
</ul>
</div>
</div>
In the controller:
$scope.get_Sub_Categories = function(category_id) {
$http({
url: base_url + 'main/json_get_list_sub_categories',
data: {
category_id: category_id
},
method: "POST"
}).success(function(data) {
$scope.list_sub_categories = data;
});
}
This time the page is loaded only once.
If I press the button the proper sub-categories are displayed BUT of course not only for the corresponding category but FOR ALL, because i am modifying the var in the global scope.
THE AIM:
What I want to obtain is simply displaying all the proper sub-categories for each category.
Without using a button, but simply see all the proper content as soon as the page load.
But i don't understand how can this be done properly in AngularJs.
THE QUESTION:
How can i properly execute a function inside a ng-repeat that return and display different data for each loop?
EDIT - DUMP OF EXAMPLE OF SUB-CATEGORIES FOR ONE CATEGORY:
[{
"sub_category_id": "1",
"name": "SUB_CATEGORY_1",
"category_id_parent": "1",
"status": "VISIBLE"
}, {
"sub_category_id": "2",
"name": "SUB_CATEGORY_2",
"category_id_parent": "1",
"status": "VISIBLE"
}, {
"sub_category_id": "3",
"name": "SUB_CATEGORY_3",
"category_id_parent": "1",
"status": "VISIBLE"
}, {
"sub_category_id": "4",
"name": "SUB_CATEGORY_4",
"category_id_parent": "1",
"status": "VISIBLE"
}]
Calling a function inside ng-repeat is same as normal one. Since you need to display the sub categories at the time of page loading its better to get these data beforehand.
Asynchronously loading sub categories will not fit into this scenario.
Here is a minimal snippet achieving this (JS Fiddle)
<div ng-app="app" ng-controller="ctrl">
<div ng-repeat="category in model.categories"> <span> Category: {{ category.name }} </span>
<p ng-repeat="subCategory in getSubCategories(category.Id)">{{ subCategory.name }}</p>
</div>
</div>
Controller
angular.module("app", [])
.controller('ctrl', ['$scope', function ($scope) {
$scope.model = {
categories: [{
"Id": 1,
name: '1'
}, {
"Id": 2,
name: '2'
}],
subCategories: [{
"parentId": 1,
name: 'a1'
}, {
"parentId": 1,
name: 'a2'
},
{
"parentId": 2,
name: 'a3'
}]
}
$scope.getSubCategories = function(parentId){
var result = [];
for(var i = 0 ; i < $scope.model.subCategories.length ; i++){
if(parentId === $scope.model.subCategories[i].parentId){
result.push($scope.model.subCategories[i]);
}
}
console.log(parentId)
return result;
}}])
The subcategory example did not work for my case and it took my code into an infinte loop for some reason. may be because i was using an accordion.
I achieved this function call inside ng-repeat by using ng-init
<td class="lectureClass" ng-repeat="s in sessions" ng-init='presenters=getPresenters(s.id)'>
{{s.name}}
<div class="presenterClass" ng-repeat="p in presenters">
{{p.name}}
</div>
</td>
The code on the controller side should look like below
$scope.getPresenters = function(id) {
return SessionPresenters.get({id: id});
};
While the API factory is as follows:
angular.module('tryme3App').factory('SessionPresenters', function ($resource, DateUtils) {
return $resource('api/session.Presenters/:id', {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET', isArray: true
},
'update': { method:'PUT' }
});
});
I think that the good solution here is to use Angular Directive.
You can see an example of directive used in a ng-repeat here : Angular Directive Does Not Evaluate Inside ng-repeat
For more information on directives, you can check the official documentation : https://docs.angularjs.org/guide/directive
I would create a factory for category then move your get_sub_categories function into this new factory.
I've been reading a lot on angular scopes and inheritance but I can't get my head around this problem. Here is the HTML I'm using:
<div class="sensorquery-sensor" ng-repeat="sensor in query.sensors" ng-controller="SensorsCtrl">
<select class="form-control"
ng-model="selected.sensor"
ng-options="sensor.name for sensor in parameters.sensors">
</select>
<select class="form-control"
ng-model="selected.definition"
ng-options="definition.value for definition in definitions">
</select>
<select class="form-control"
ng-model="selected.operation"
ng-options="operation for operation in operations">
</select>
</div>
As you can see, I have an ng-repeat based on query.sensors. The values stored in this query.sensors array should be simple:
{
name: 'sensor1',
type: 'temperature'
}
But I want to use a child controller: SensorsCtrl to handle more logic per sensor and hide the complexitiy of sensors. A sensor can look like:
{
name: 'sensor1',
attributes: [
'model',
'brand'
],
definitions: [
{
datatype: 'double',
value: 'temperature'
},
{
datatype: 'integer',
value: 'pressure'
},
{
datatype: 'string',
value: 'color'
}
]
}
So it's in my SensorsCtrl controller where I want to put the selection logic:
$scope.$watch('selected.sensor', function(sensor) {
$scope.definitions = sensor.template.definition;
});
$scope.$watch('selected.definition', function(definition) {
if (definition.datatype === 'string') {
$scope.operations = ['Count'];
} else {
$scope.operations = ['Max', 'Min'];
}
$scope.selected.operation = _.first($scope.operations);
});
How do I keep the link with the parent query.sensors[$index] while transforming the sensor as the user selects different sensors and definitions?
Setting up a watcher on selected and updating the query.sensors array triggers an infinite $digest loop.
I found the solution which was right before my eyes:
<div class="sensorquery-sensor" ng-repeat="sensor in query.sensors" ng-controller="SensorsCtrl">
<!-- ... -->
</div>
The sensor is a reference to the original object of the parent query.sensors. An it's created in the scope of the sub-controller.
So in my SensorsCtrl controller, I can just watch:
$scope.$watch('sensor.definition', function(definition) {
/* ... */
});
So I can put hide some complexity in this controller while maintaining a proper link to the original element.
It does not answer the question of maintaining a less complex object but it's a different question I guess.