I'm looking for two things:
To push items in a nested array with Angularjs
To understand how it works exactly.
I've been looking for answers on differents previous topic but I didn't manage to come to a solution.
Actually, I want to use an Add Item button to push an item in a items array under a facture object.
Here is my controller:
PlasmaCrm.controller('FacturesSoloController', function($scope, $stateParams, Facture ) {
Facture.get({ id: $stateParams.factureId }, function(data) {
$scope.facture = data;
});
$scope.ajouterItem = function(index, item){
$scope.facture.items[index].item.push({
description: 'Test'
});
}
});
And here is my data structure (as returned by my API)
{
"id":10200,
"client_id":1,
"lead_id":1,
"courtedescription":"Description test",
"etat":"En attente",
"created_at":"2015-02-21 15:07:17",
"updated_at":"2015-02-21 15:07:17",
"items":[
{
"id":1,
"facture_id":10200,
"description":"Item num\u00e9ro 1",
"prix":"15.00",
"tps":"0.75",
"tvq":"1.50",
"grandtotal":"17.25",
"created_at":"2015-02-21 15:07:18",
"updated_at":"2015-02-21 15:07:18"
},
{
"id":2,
"facture_id":10200,
"description":"Deuxi\u00e8me item quoi",
"prix":"135.00",
"tps":"6.75",
"tvq":"13.47",
"grandtotal":"155.22",
"created_at":"2015-02-21 15:07:18",
"updated_at":"2015-02-21 15:07:18"
}
]
}
Of course my HTML contains a button:
<form ng-submit="ajouterItem(item)">
<button class="btn btn-primary">Ajouter un item</button>
</form>
Actually I got an error (undefined) when I press to button. What is wrong?
For those who are still looking for pushing data in the nested array can refer below example of Comments and Replies :
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<!--Comment section-->
<ul ng-repeat="comment in comments track by $index" style="background: skyblue; padding: 10px;">
<li>
<b>Comment {{$index}} : </b>
<br>
{{comment.comment}}
<!--Reply section-->
<ul ng-repeat="reply in comment.reply track by $index">
<li><i>Reply {{$index}} :</i><br>
{{reply.comment}}</li>
</ul>
<!--End reply section-->
<input type="text" ng-model="reply" placeholder=" Write your reply." />Reply
</li>
</ul>
<!--End comment section -->
<!--Post your comment-->
<b>New comment</b>
<input type="text" placeholder="Your comment" ng-model="comment" />
Post
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
//Comments object having reply oject
$scope.comments = [{ comment: 'hi', reply: [{ comment: 'hi inside commnet' }, { comment: 'hi inside commnet' }] }];
//push reply
$scope.insertReply = function (index, reply) {
$scope.comments[index].reply.push({ comment: reply });
}
//push commnet
$scope.newComment = function (comment) {
$scope.comments.push({ comment: comment, reply: [] });
}
});
</script>
</body>
</html>
Since there is no item property inside the items array objects, you cant push to it. You have to add:
$scope.facture.items[index].item = []
before you can push to it. Also check your functions parameters as Marc states in his comment. Since we can't see all of the markup it is unclear what is passed to the function, a simple console.log() will show you that ofcourse.
I found the answer, it was finaly simpler than I first thought:
$scope.ajouterItem = function(){
$scope.facture.items.push({
description: 'Test'
});
}
First, create a variable to fill, delete, and add items. Next, assign this variable to the array inside the model.
PlasmaCrm.controller('FacturesSoloController', function($scope, $stateParams, Facture )
{
$scope.items= [];
Facture.get({ id: $stateParams.factureId }, function(data) {
$scope.facture = data;
$scope.items = $scope.facture.items;
});
$scope.ajouterItem = function(item){
$scope.items.push(item);
$scope.facture.Items = $scope.items;
}
});
In this way, you can also edit the previous information and add new information. Since we first set "items". To remove the same as usual :
$scope.RemoveItem = function (index) {
$scope.facture.Items.splice(index, 1);
};
Related
Hi I'm using angularJs in my client side. I have a view where a user can add and remove item like this:
app.controller('demoController', function($scope) {
// initial items
$scope.items = [
'item one',
'item two',
'item three'
];
// add an item
$scope.add = function() {
$scope.items.push($scope.input);
};
// remove an item
$scope.remove = function(index) {
$scope.items.splice(index, 1);
};`enter code here`
});
When the user finish, I want he clicks on a button. And after I will send all the items added and removed to a server to update database. I can't do this on each click because I need all the information to fill an email in my server part. I know how to remove and add item but I don't how to found removed items and add items and send them to the server. Please any one know how I can do this?
Thanks a lot.
You can do it with only using 1 array. You just have to create a new property and set it to true - if removed -, or false otherwise.
Then in your back-end you can get all the removed items accessing this property.
See the example below:
(function() {
'use strict';
angular
.module('app', [])
.controller('demoController', demoController);
demoController.$inject = ['$scope'];
function demoController($scope) {
// initial items
$scope.items = [
{
"name":"item one",
"removed":false
},
{
"name":"item two",
"removed":false
},
{
"name":"item three",
"removed":false
}
];
// add an item
$scope.add = function() {
$scope.items.push({
"name": $scope.input,
"removed": false
});
};
// remove an item
$scope.remove = function(index) {
$scope.items[index].removed = !$scope.items[index].removed;
};
}
})();
<!DOCTYPE HTML>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" />
</head>
<body ng-controller="demoController">
<table class="table table-hover">
<thead>
<tr>
<td>Name</td>
<td>Removed?</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items track by $index">
<td ng-bind="item.name"></td>
<td ng-bind="item.removed"></td>
<td>
<button type="button" class="btn btn-danger btn-sm" ng-click="remove($index)">Remove item</button>
</td>
</tr>
</tbody>
</table>
<hr>
<input type="text" class="form-control" ng-model="input" placeholder="Type to add">
<button type="button" class="form-control btn btn-primary btn-sm" ng-click="add()">Add item</button>
</body>
</html>
Note: If you don't want to show the removed items, you can simply check in your tr:
<tr ng-repeat="item in items track by $index" ng-if="!item.removed">
Now if you want to send both added and removed you have to actually store the removed ones somewhere either in the object itself with a flag like #developer033 suggested or either in an other object.
For me it is better to store all added and removed elements in one object. Now you do not need to click a button and send the change on every add or remove. When you are done with adding and removing you can just simply send the whole object with AJAX request to the server where you can do your logic:
function demoController($scope, $http, $q) {
$scope.submitItems = function(){
sendItems($scope.items).then(function () {
alert("Successfully deleted PT");
}, function (error) {
alert(error);
});
};
// ....
var sendItems = function (items) {
var request = $http({
url: _SERVER + 'edit/sendItems', // for example
method: 'POST',
data : items
params: {
}
});
return request.then(function (data) {
return $q.when(data);
}, function (error) {
return $q.reject(error);
});
}
// ....
}
It is a good practise to have a service from where you call the server and where this method sendItems should be. But we try to keep at as simple as possible.
Now in your rest controller in Spring you have to specify #RequestBody param:
#RequestMapping(value = "/sendItems", method = RequestMethod.POST)
public String editProductParameters(#RequestBody ArrayList<Item> items) {
//your logic goes here
return "Success"
}
Where the Item.class should consist the fields: String name and boolean remove also should have a deffault constructor(deffault constructur is specified if there are none implementations of constructurs in the class or if there is a constructor with no arguments) also create getters and setter about the two fields. Thouse are the requirements that are needed to pass the whole array of objects($scope.items) from the client to the server with default mapping.
Good luck
I'm trying to filter data by check box and search field. Code is working fine when i'm giving the static json array to $scope.students variable but it does not working and nothing showing when i'm getting same json array through php file using $http.get("data.php").then(function(response) {...});
HTML
<div ng-app="app" ng-controller="ctrl">
<input type="text" ng-model="findname" placeholder="Search Name">
<ul>
<li ng-repeat="tech in technologyArray">
<label>
<input type="checkbox" ng-model="tech.on">{{tech.u_proffession}}
</label>
</li>
</ul>
<ul>
<li ng-repeat="stu in students | filter:{u_name: findname} | customFilter:(technologyArray|filter:{on:true})">
<strong>Name :{{stu.u_name}}</strong> ({{stu.u_proffession}})
</li>
</ul>
</div>
JS
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.technologyArray = [{
u_proffession: "developer",
on: false
}, {
u_proffession: "driver",
on: false
}];
$scope.students = [
{"u_name":"adrian","u_mail":"Aenean.sed#ut.net","u_images":"11.jpg","u_proffession":"developer"},
{"u_name":"shelley","u_mail":"urna#In.ca","u_images":"11.jpg","u_proffession":"developer"},
{"u_name":"nasim","u_mail":"sed#acurna.edu","u_images":"11.jpg","u_proffession":"driver"}
];
})
.filter('customFilter', function() {
return function(input, techs) {
if(!techs || techs.length === 0) return input;
var out = [];
angular.forEach(input, function(item) {
angular.forEach(techs, function(tech) {
if (item.u_proffession === tech.u_proffession) {
out.push(item);
}
});
});
return out;
}
});
Above code is working fine as i want but i wanted to fetch the data from php file now its working with static json data. So when i'm adding below script instead of static json array then it does not working.
controller('ctrl', function($scope) {
....
$http.get("data.php").then(function(response) {
$scope.students= response.data.records
});
})
There is same json array in the data.php
{"records":[{"u_name":"adrian","u_mail":"abc#gmail.net","u_proffession":"developer"},{...}]}
Can anyone guide me how can i fix the issue. I would like appreciate if someone guide me regarding this. Thank You.
I am accessing the instagram API to fetch photos that a specific user has liked and the first comment that said user has posted. However I only want to retrieve the URL from the text for example, the user tellasaur first comment is:
"text":"Check out this link http://www.domain.com",
I only want to retrieve http://www.domain.com. Here is my code so far:
So I want to apply a regex on this part {{p.comments.data|getFirstCommentFrom:'tellasaur'}}"
but not sure how.
JS
angular.module('app',[])
.filter('getFirstCommentFrom',function(){
return function(arr, user){
for(var i=0;i<arr.length;i++)
{
if(arr[i].from.username==user)
return arr[i].text;
}
return '';
}
})
.controller('TestCtrl', function($scope){
$scope.pics = [
{ "images":{
"low_resolution":{
"url":"https:\/\/scontent.cdninstagram.com\/hphotos-xaf1\/t51.2885-15\/s320x320\/e15\/11243658_841091872640638_1858051687_n.jpg",
"width":320,
"height":320
},
},
"comments":{
"count":38,
"data":[
{
"created_time":"1436314585",
"text":"Check out this link http://www.domain.com",
"from":{
"username":"tellasaur",
"profile_picture":"https:\/\/igcdn-photos-b-a.akamaihd.net\/hphotos-ak-xfp1\/t51.2885-19\/11142181_1606991566225969_1204610350_a.jpg",
"id":"174270894",
"full_name":"kristella"
},
"id":"1024203434844916571"
},
{
"created_time":"1436317671",
"text":"Wow",
"from":{
"username":"sbcarol2002",
"profile_picture":"https:\/\/igcdn-photos-b-a.akamaihd.net\/hphotos-ak-xfp1\/t51.2885-19\/10707061_359756607505353_826681437_a.jpg",
"id":"1280059782",
"full_name":"Susan Long"
},
"id":"1024229322726738700"
},
{
"created_time":"1436320519",
"text":"\ud83d\udc93 dreamyy",
"from":{
"username":"veekster",
"profile_picture":"https:\/\/igcdn-photos-h-a.akamaihd.net\/hphotos-ak-xtf1\/t51.2885-19\/11117059_1743047859255223_204225114_a.jpg",
"id":"31179150",
"full_name":"Victoria Wright"
},
"id":"1024253210688915485"
}
]
}
}
]
});
HTML NG-LOOP
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app" ng-controller="TestCtrl">
<li ng-repeat="p in pics">
<img ng-src="{{p.images.low_resolution.url}}" />
<p></p>
</li>
</div>
See this answer on how to regex match urls in text, your solution is in there somewhere
I have a model, which will be related to a number of other models. Think of a stack overflow question, for example, where it is a question related to tags. The final Object might look as follows before a POST or a PUT:
{
id: 28329332,
title: "checkboxes that append to a model in Angular.js",
tags: [{
id: 5678,
name: "angularjs"
}, {
id: 890,
name: "JavaScript"
}]
}
So far, I have the following controller:
.controller('CreateQuestionCtrl',
function($scope, $location, Question, Tag) {
$scope.question = new Question();
$scope.page = 1;
$scope.getTags = function() {
Tag.query({ page: $scope.page }, function(data) {
$scope.tags = data;
}, function(err) {
// to do, error when they try to use a page that doesn't exist
})
};
$scope.create = function() {
$scope.question.$save(function(data) {
$location.path("/question/" + data.id);
});
};
$scope.$watch($scope.page, $scope.getTags);
}
)
So I display all of the tags, paginated, on the page. I want them to be able to select the given tags and append it to my model so that it can be saved.
How can I create a checkbox interface where it updates the $scope.question with the selected other models?
EDIT: think I might be part of the way there
<div class="checkbox" ng-repeat="tag in tags.objects">
<label><input
type="checkbox"
ng-change="setTag(tag.id)"
ng-model="tag"
> {{ tag.name }}
</div>
Then on the controller
$scope.setTag = function(id) {
Tag.get({id: id}, function(data) {
// don't know what now
})
}
Basically, it takes a directive to approach your goal Take a look at the plunker I wrote for you. As you can see, in the list of selected tags the text property of each tag is displayed, it means that the object structure is kept. In your case, you would bind the $scope.question.tags array as the collection attribute and each tag from the $scope.tags as the element attribute.
Here a codepen for multiple check-boxes bound to the same model.
HTML
<html ng-app="codePen" >
<head>
<meta charset="utf-8">
<title>AngularJS Multiple Checkboxes</title>
</head>
<body>
<div ng:controller="MainCtrl">
<label ng-repeat="tag in model.tags">
<input type="checkbox" ng-model="tag.enabled" ng-change="onChecked()"> {{tag.name}}
</label>
<p>tags: {{model.tags}}</p>
<p> checkCount: {{counter}} </p>
</body>
</html>
JS
var app = angular.module('codePen', []);
app.controller('MainCtrl', function($scope){
$scope.model = { id: 28329332,
title: "checkboxes that append to a model in Angular.js",
tags: [{
id: 5678,
name: "angularjs",
enabled: false
}, {
id: 890,
name: "JavaScript",
enabled: true
}]
};
$scope.counter = 0;
$scope.onChecked = function (){
$scope.counter++;
};
});
I found a great library called checklist-model worth mentioning if anyone is looking up this question. All I had to do was this, more or less:
<div class="checkbox" ng-repeat="tag in tags">
<label>
<input type="checkbox" checklist-model="question.tags" checklist-value="tags"> {{ tag.name }}
</label>
</div>
Found this on googling "directives for angular checkbox".
I have a list of products where the name is a link to the product's details view. The list of products is the "Results" view
Samsumg
iPhone
When the user clicks on a product, the "Details" template is shown, and the "Results" template is not shown; at least that is the behavior that I want.
I am using the following code to accomplish this behavior, and have the jsFiddle here http://jsfiddle.net/justinnafe/mLf5G/:
<div data-bind="template: displayMode"></div>
<script type="text/html" id="Result">
<ul data-bind="foreach: products">
<li></li>
</ul>
</script>
<script type="text/html" id="Details">
<p data-bind="text: name"></p>
<p data-bind="text: description"></p>
</script>
and the javascript:
var view = {
name: "Result"
};
var initialProducts = [{
name: "Samsumg",
description: "The best phone"
},{
name: "iPhone",
description: "The other best phone"
}];
var viewModel = (function (){
var products = ko.observableArray(initialProducts),
displayMode = ko.observable(view),
switchDisplayMode = function(item){
if (displayMode() == 'Result') {
displayMode({ name: "Details", data: item });
}
else {
displayMode({ name: "Result", data: item });
}
};
return {
products: products,
displayMode: displayMode,
switchDisplayMode: switchDisplayMode
};
})();
ko.applyBindings(viewModel);
I am trying to pass that product to the Details template, but have been unsuccessful. Any clues or tips would be helpful.
I am currently getting a "ReferenceError: products is not defined" error when I click on a link, but not sure how to fix it. Maybe if I fix that error, the switching views will behave as expected.
In your function to switch the template, you are forgetting that your displayMode observable is holding an object - not a string value.
So inside switchDisplayMode, displayMode() = { name: 'Result' }. Switching that to displayMode().name fixes the problem. See updated fiddle