ng-click function is not called with onclick in a AngularJS? - javascript

I have to call the ng-click function with the onClick but in my case ng-click function is not
//Controller function
$scope.editProductDetail = function(productObject) {
$scope.getProduct = productObject;
}
<a href="#"
onclick="document.getElementById('editProduct').style.display='block'" ng-click="editProductDetail(list)" target="_self">
</a>
call but model is open with onClick function?

It seems you're trying to set a class to the selected item from a product list, it seems you're confusing some AngularJS concepts.
If you're using AngularJS there's no need to use both onclick and ng-click.
If you want to show all products from your list you may want to use ng-repeat.
You need to initialize your Module for your AngularJS controller to load, and the controller must be within the module in the HTML code.
I've done an example bellow based on your code, it might help if you edit your answer and add your complete code.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.count = 0;
$scope.selectedIndex = 0;
$scope.editProductDetail = function (index) {
$scope.selectedIndex = index;
};
$scope.productList = [
{ name: 'Product 1', price: '1,00 U$' },
{ name: 'Product 2', price: '2,00 U$' },
{ name: 'Product 3', price: '3,00 U$' }
];
});
.selected-item {
display: block;
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl" >
<h2>Selected Item Number: {{ selectedIndex + 1}}</h2> <!-- I've added +1 since index starts at 0 -->
<div ng-repeat="item in productList">
{{ item.name}} {{item.price}}
</div>
</div>

As debabrata was saying you don't need to use both, just use something like this:
// Your controller
$scope.editProductDetail = function(productObject) {
$scope.setDisplayBlock = true;
$scope.getProduct = productObject;
}
// Your HTML
<span id="editProduct" ng-class="{'css-class-with-display-block': setDisplayBlock}">The element to change</span>

Related

AngularJS: How to freeze orderBy in ng-repeat during edit mode

I'm using md-data-table and I have add sorting options based on column.
Below, presented my html(pug format) code:
table(md-table md-row-select multiple='' ng-model='vm.selected' md-progress='promise')
//- columns
thead(md-head class='back-color')
tr(md-row)
th(md-column ng-click='vm.orderingBy(name)')
span Name
th(md-column ng-click='vm.sortingBy(code)')
span Code
//- rows
tbody(md-body)
tr(md-select='record' md-select-id='id' ng-repeat='record in vm.records | orderBy:vm.orderByColumn)
//- name
td(md-cell)
p(ng-hide='vm.columns.edit') {{record.name}}
md-input-container(ng-if='vm.columns.edit' class='no-errors-spacer md-no-margin')
input(ng-model='record.name' md-select-on-focus)
//- code
td(md-cell)
p(ng-hide='vm.columns.edit') {{record.sorting_code}}
md-input-container(ng-if='vm.columns.edit' class='no-errors-spacer md-no-margin')
input(ng-model='record.code' md-select-on-focus)
My AngularJS(Javascript) code presented below:
vm.orderByColumn = 'name';
vm.orderingBy = function(ordering) {
vm.orderByColumn = ordering;
}
The problem is when the table is ordered by 'code' and I'm trying to edit the record's code, the order of records changing while you change the value of code. So, the result is very confused.
I'm thinking if there is any way to freeze the order while I'm in edit mode.
Outsource your orderBy logic into your controller and make it block in edit mode by using a simple switch variable like in this example fiddle. I hope this working example will help you to implement this logic inside your application.
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope, orderByFilter) {
$scope.edit = false;
$scope.data = [{
name: 'Frank'
},{
name: 'Peter'
},{
name: 'Basti'
},{
name: 'Sven'
},{
name: 'Franky'
},{
name: 'Sveny'
},{
name: 'bob'
}];
$scope.order = {
column: '',
revers: false
}
$scope.toggleEditMode = function () {
$scope.edit = !$scope.edit;
}
$scope.orderBy = function (column) {
if (!$scope.edit) {
$scope.order.column = column;
$scope.order.reverse = !$scope.order.reverse; //toggle revers
$scope.data = orderByFilter($scope.data, $scope.order.column, $scope.order.reverse);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<div>
<h3 ng-click="orderBy('name')">
Name
</h3>
<p ng-repeat="item in data">
<input type="text" ng-model="item.name" ng-if="edit" />
<span ng-if="!edit">{{ item.name }}</span>
</p>
</div>
<button ng-click="toggleEditMode()">
Toggle edit mode
</button>
</div>
</div>
I had this issue for a while and I've found a pretty simple solution. I made the sorting method by myself using $filter,
On my case : Instead of
<tr ng-repeat="schedule in schedules | orderBy:filerTable2:filterasc track by $index">
I just put
<tr ng-repeat="schedule in schedules">
And I used setFiler method to sort the list using filter parameter as the filter name.
$scope.setFiler = function(filter){
if($scope.filerTable2 == filter){
$scope.filterasc = !$scope.filterasc;
}
else{
$scope.filerTable2 = filter;
$scope.filterasc = false;
}
$scope.schedules = $filter('orderBy')($scope.schedules, filter, $scope.filterasc);
};

Remove object from ng-repeat

I have a PhoneGap + Onsen UI + AngularJS app in the works, where I have a list in the view, where the items will be fetched from the controllers variable.
I want to be able to remove items from this list, by clicking on them.
The list looks like this:
<ons-list>
<ons-list-item modifier="tappable" class="item" ng-repeat="citem in completeditems" ng-click="delete(citem)">
<ons-row>
<ons-col>
<div class="titlediv">
<header>
<span class="item-title">{{citem.name}}</span>
</header>
</div>
<div class="item-dates">
<span class="item-start">{{citem.start}}</span>
</div>
</ons-col>
</ons-row>
</ons-list-item>
</ons-list>
The completeditems object in the $scope looks like this:
var completeditemname = "item" + i;
$scope.completeditems[completeditemname] = {
id : "ID",
name : "Name for it",
start: "Start date"
}
Tried the following method, but it didn't work out:
$scope.delete = function(item) {
var index = $scope.completeditems.indexOf(item);
$scope.completeditems.splice(index,1);
//$scope.completeditems.remove(item); //tried this aswell
$scope.$apply() //i need this to update the view
}
You do not need the $scope.$apply() invocation. As you are making alterations to scope variables the digest cycle will be triggered anyhow and you will be encountering an error because of this I believe.
UPDATED:: You're working with an actual object by the looks of it so I've updated the code in the plunker to help you out. It means altering the ng-repeat to use both key and value.
Here is a simple plunkr showing a basic example of what you are trying to do with a one liner in the delete function http://plnkr.co/edit/NtQD....
<body ng-app="myApp">
<div ng-controller="myController as ctrl">
<ul ng-repeat="(key, value) in ctrl.items track by key">
<li ng-click="ctrl.delete(key)">{{value}}</li>
</ul>
</div>
</body>
var myApp = angular.module('myApp', [])
.controller('myController', [
'$scope',
function($scope) {
var self = this;
self.items = {
item1: {
id: 1,
name: 'a'
},
item2: {
id: 2,
name: 'b'
},
item3: {
id: 3,
name: 'c'
}
};
self.delete = function(key) {
delete self.items[key];
};
}
]);
Hope that helps you out!
$scope.$apply() should only be used when changes are coming in from outside the Angular framework. Since your delete() function is being called from an ng-click, it is already being managed by Angular and calling $apply() will raise a "$digest is already in progress" error (check your browser console). Removing that call will most likely get your code working.

Understanding scope, ng-click and the angular-way

While working on the phone tutorial i wondered how to implement this use case
user clicks on add phone
the function addItem is fired and the phone.id is passed
the relevant phone is retrieved and the quantity increased by 1
the increased quantity should be displayed in the input
You can find my codepen demo here and this is the relevant code
<ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp">
<b>{{phone.name}} </b>
<i ng-click="addItem(phone.id)"> add phone</i>
<input name='{{phone.id}}'
value='{{phone.qty}}'
ng-readonly='{{phone.orderReadonly}}' /><br />
<p>{{phone.snippet}} </p>
</li>
</ul>
and the javascript
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', function($scope) {
$scope.phones = [
{'id': 1, 'name': 'Mui 1'
,'snippet': 'Our newcomer from asia.'
,'orderReadonly' : 'false', 'qty': 4}
....
,{'id': 4, 'name': 'Msft Lumiaâ„¢'
,'snippet': 'Who knows what windows 10 will bring'
,'orderReadonly' : 'true','qty': 2}
];
$scope.orderProp = 'id';
$scope.addItem = function(phone_id) {
// from http://stackoverflow.com/questions/15610501/
var found = $filter('filter')($scope.phones, {id: phone_id}, true);
if (found.length) {
found[0].qty = found[0].qty + 1;
} else {
$scope.selected = 'Not found';
}
}
});
Current status
passing the id works
finding the phone does not work: var found = $filter('filter')($scope.phones, {id: phone_id}, true); // found in http://stackoverflow.com/questions/15610501/
increasing quantity does not work
My questions are
if and how onclick / ng-click should be used in the angular way
how to solve my requirement - increase phone quantity onclick on <i>add phone</i>
I don't know why qty doesn't work - it should, unless your filter doesn't find a match.
But you shouldn't even be doing this. Instead of passing the id of the object and then locating the object to change its property, just pass the object phone itself:
<i ng-click="addItem(phone)"> add phone</i>
Then, in the controller, simply do this:
$scope.addItem = function(phone) {
phone.qty = phone.qty + 1;
}
Summarising the two above answers. The "++" increment will not work on the variable or object property from the "ng-click" directive, so instead you should use:
variable = variable + 1
And in connection to the original question the
<i ng-click="phone.qty = phone.qty + 1"> add phone</i>
will do the trick.
To answer your first question:
Using ng-click runs an angular expression inside Angular's scope. If you use the onclick simply runs javascript code.
So if you have some variable 'numPhones' initialized inside your controller, then you can have:
ng-click="numPhones = numPhones + 1"
and the numPhones variable will be incremented.
On the other hand:
onclick="numPhones = numPhones + 1"
doesn't reference the surrounding angular scope.
So if you're using Angular, you probably wouldn't want onclick at all.
Here's an example:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script>
angular.module('phones', [])
</script>
</head>
<body ng-app='phones'>
<div>
{{ numPhones }}
<button ng-click="numPhones = numPhones + 1"> add 1</button>
</div>
</body>
</html>

Custom directive: How evaluate bindings with dynamic HTML

Setup:
Very simplified HTML:
<td ng-repeat="col in cols">
<div ng-bind-html="col.safeHTML"></div>
</td>
JS controller:
$scope.cols = [
{
field : 'logo',
displayName : 'Logo',
cellTemplate: '<div style="color:red">{{col}}</div>'
},
{
field : 'color',
displayName : 'Color',
cellTemplate: '<div style="color:green">{{col}}</div>
}
];
JS link directive link function:
for (var i = 0, j = $scope.cols.length;
i < j;
i++) {
if ($scope.cols[i].hasOwnProperty('cellTemplate')) {
$scope.cols[i].safeHTML = $sce.trustAsHtml($scope.cols[i].cellTemplate);
}
}
And it is escaping correctly the HTML but the bindings ({{some_var}}) are not being interpolated.
How can make Angular compute the bindings in the safe HTML? I tried to use several variations of bind like ngBindTemplate but was for no use :(
You actually want to use the $compile service if you plan to dynamically compile angular components and add them to the DOM manually.
With a little bit of custom directive work, you can make this work pretty easily.
function compileDirective($compile) {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
//Watch for changes to expression
scope.$watch(attrs.compile, function(newVal) {
//Compile creates a linking function
// that can be used with any scope
var link = $compile(newVal);
//Executing the linking function
// creates a new element
var newElem = link(scope);
//Which we can then append to our DOM element
elem.append(newElem);
});
}
};
}
function colsController() {
this.cols = [{
name: "I'm using an H1",
template: "<h1>{{col.name}}</h1>"
}, {
name: "I'm using an RED SPAN",
template: "<span style=\"color:red\">{{col.name}}</span>"
}];
}
angular.module('sample', [])
.directive('compile', compileDirective)
.controller('colsCtrl', colsController);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0-beta.4/angular.min.js"></script>
<div ng-app="sample">
<ul ng-controller="colsCtrl as ctrl">
<li ng-repeat="col in ctrl.cols">
<!-- The "compile" attribute is our custom directive -->
<div compile="col.template"></div>
</li>
</ul>
</div>

reflect change made by object affectation to scope

I try to cancel changes made to a ng-repeat item by re-affecting a copy of it that I made just before editing it, the original object is affected but nothing change in the view. It's just plain weird, and I haven't figure out why!
http://jsfiddle.net/leseulsteve/a16j16mk/8/
<div ng-controller="MyCtrl">
<ul ng-repeat="item in list">
<li ng-click="edit(item)">{{item.description}}</li>
</ul>
{{originalDescription}}
</div>
--
function MyCtrl($scope, $timeout) {
$scope.list = [{
description: 'I love bacon'
}, {
description: "J'aime le bacon"
}];
$scope.edit = function (item) {
var originalItem = angular.copy(item);
item.description = 'aaa'; /// update the view
$timeout(function () {
item = originalItem; // doesn't update the view :((
$scope.originalDescription = item.description; // Show the original description.
}, 1000);
}
}

Categories

Resources