I have two controllers with same data depending upon language selection controller will load.When an item is clicked on the list item is loading but the problem is when other items are clicked angular ready function is not working and am seeing previously loaded item only
.controller('EnCtrl', function($scope,sharedCartService) {
var cart = sharedCartService.cart;
$scope.menu_items=[
{"p_id":"1",
"p_name":"coffe ",
"p_image_id":"coffe",
"p_price":"50"
},
{"p_id":"2",
"p_name":"Tea",
"p_image_id":"Tea",
"p_price":"50"
},
{"p_id":"3",
"p_name":"Masala",
"p_image_id":"Masala",
"p_price":"50"
}];
$scope.showProductInfo=function (id,img,name,price) {
sessionStorage.setItem('product_info_id', id);
sessionStorage.setItem('product_info_img', img);
sessionStorage.setItem('product_info_name', name);
sessionStorage.setItem('product_info_price', price);
window.location.href = "#";
};
$scope.addToCart=function(id,image,name,price){
cart.add(id,image,name,price,1);
};
})
Kctrl
.controller('kCtrl', function($scope,sharedCartService) {
var cart = sharedCartService.cart;
$scope.menu_items=[
{ "p_id": "1",
"p_name": "ಕಾಫಿ",
"p_image_id": "coffe",
"p_price": "50"
},
{ "p_id": "2",
"p_name": "ಚಹಾ",
"p_image_id": "Tea",
"p_price": "50"
},
{ "p_id": "3",
"p_name": "ಮಸಾಲಾ",
"p_image_id": "Masala",
"p_price": "50"
}];
$scope.showProductInfo=function (id,img,name,price) {
sessionStorage.setItem('product_info_id', id);
sessionStorage.setItem('product_info_img', img);
sessionStorage.setItem('product_info_name', name);
sessionStorage.setItem('product_info_price', price);
window.location.href = "#";
};
$scope.addToCart=function(id,image,name,price){
cart.add(id,image,name,price,1);
};
})
Product Controller
.controller('productCtrl', function($scope) {
//onload event
angular.element(document).ready(function () {
$scope.id= sessionStorage.getItem('product_info_id');
$scope.img= "img/"+ sessionStorage.getItem('product_info_img')+".jpg";
$scope.name= sessionStorage.getItem('product_info_name');
$scope.price= sessionStorage.getItem('product_info_price');
});
En.html
<ion-list ng-repeat="item in menu_items" >
<h2 ng-click="showProductInfo(item.p_id,item.p_image_id,item.p_name,item.p_price)" > {{item.p_name}} </h2>
<p ng-click="showProductInfo(item.p_id,item.p_image_id,item.p_name,item.p_price)">{{item.p_price}}</p>
</ion-list>
Productpage.html
<div>
<p> {{name}}</p>
<p>{{price}}</p>
</div>
Updated after comments.When an item is clicked dataupdate message is displayed.Item information is not getting
.
controller('EnCtrl', function($scope,sharedCartService,$rootScope) {
var cart = sharedCartService.cart;
$scope.menu_items=[
{"p_id":"1",
"p_name":"coffe ",
"p_image_id":"coffe",
"p_price":"50"
},
{"p_id":"2",
"p_name":"Tea",
"p_image_id":"Tea",
"p_price":"50"
},
{"p_id":"3",
"p_name":"Masala",
"p_image_id":"Masala",
"p_price":"50"
}];
$scope.showProductInfo=function (id,img,name,price) {
$rootScope.$broadcast('dataUpdate', {id: id,img: img,name: name,price: price})
window.location.href = "#";
};
$scope.addToCart=function(id,image,name,price){
cart.add(id,image,name,price,1);
};
})
Product Controller
.controller('productCtrl', function($scope,$rootScope) {
$rootScope.$on('dataUpdate', function(data) {
$scope.id = data.id;
$scope.img = data.img;
$scope.name = data.name;
$scope.price=data.price;
})
})
Plunker demo
https://plnkr.co/edit/zhvBzOzDtgOiTEGjBqAp?p=preview
#user3698911, in addition to #Bartek Fryzowicz's answer,
You may also want to look at:
angular.element
Note from angular:
(deprecated, use angular.element(callback) instead of
angular.element(document).ready(callback))
Actually .ready method is not Angular function but jqLite method (or jQuery method if you included it on your page; by default angular uses jqLite but if you include jQuery it will be used instead). angular.element(document) returns an element wrapped in jqLite object and ready is method of this object. Back to your main problem: 'ready' method callback is called only once when DOM is fully loaded, it's not called again until next page reload. Please check docs of ready method
You can broadcast an event with your data on $rootScope in click handler and then access this data in another controller in the event listener.
So in you click handler do this:
$rootScope.$broadcast('dataUpdate', {id: id, name: name, img: img, price: price})
And in product controller add this (use event data to updated controller $scope):
$rootScope.$on('dataUpdate', function(data) {
$scope.id = data.id;
$scope.img = data.img;
$scope.name = data.name;
...
});
Update after comments questions
You have to inject $rootScope into each controller in which you want to use it:
.controller('EnCtrl', function($scope,sharedCartService, $rootScope) {
...
.controller('productCtrl', function($scope, $rootScope) {
Answer update
I've noticed that you redirect in your click handler. So please try just removing ready handler so that your controller reads localStorage every time it's initialised:
.controller('productCtrl', function($scope) {
$scope.id= sessionStorage.getItem('product_info_id');
$scope.img= "img/"+ sessionStorage.getItem('product_info_img')+".jpg";
$scope.name= sessionStorage.getItem('product_info_name');
$scope.price= sessionStorage.getItem('product_info_price');
}
Related
I am having an issue with a select. I have a profile view that utilizes the profileCtrl. In that controller I get the users info from the db and put it into scope. I also use a service to grab all the info from the config table in the db and insert that into rootScope. My question and answers come from the config table (rootScope) the user's selected answer comes from the user info (scope). I need a select that preselects whatever answer the user has in the db. Below is my code.
Profile Controller:
app.controller('profileCtrl', function ($scope, $log, $http, $timeout, Data, Auth, dataShare, $sessionStorage, $rootScope, $confirm) {
$timeout(function() {
// get user's info from db and put it into scope
Data.get('profile/'+$rootScope.user.uid).then(function(data){
$scope.profs = data.data;
$scope.buttonText = 'Update Profile';
});
}, 100);
// get the configs from the configs service and put it in the rootScope
dataShare.getconfigs().then(function(data){
$rootScope.configs = data;
// get the answers from the config table for the select's options
$scope.availableAnswers = [
{ answer: $rootScope.configs[0].a1 },
{ answer: $rootScope.configs[0].a2 },
{ answer: $rootScope.configs[0].a3 },
{ answer: $rootScope.configs[0].a4 },
{ answer: $rootScope.configs[0].a5 }
];
});
// function executed on change from the select
$scope.selectedItemChanged = function() {
$log.log($scope.selectedAnswer);
}
// inline edit title
$scope.updateUser = function(data) {
Data.put('config/'+data.id, {profile_page_title:data.profile_page_title}).then(function (result) {
Data.toast(result);
});
};
$scope.saveProfile = function (profile) {
profile.roles = $rootScope.user.roles;
if(profile.uid.length > 0){
Data.put('profile/'+profile.uid, profile).then(function (result) {
$sessionStorage.user = profile;
$rootScope.user = $sessionStorage.user;
Data.toast(result);
});
}else{
Data.post('profile', profile).then(function (result) {
$rootScope.name = profile.name
Data.toast(result);
});
}
};
});
HTML: (I have condensed the code to be read easily)
<section class="row" id="" ng-repeat="profile in profs">
<div class="col-xs-12" id="questionWidget">
<h4>{{configs[0].question}}</h4>
<!-- user's answer from db -->
{{profs[0].answer}}
<select ng-model="selectedAnswer" ng-change="selectedItemChanged()" ng-options="a.answer for a in availableAnswers">
</select>
</div>
</section>
Alright, so I made a plunk, and this is what I came up with. This will set the select option if the professor's current answer exists in the list.
The reason ng-init didn't work is because the selectedAnswer model is actually expecting to see an object with property 'answer'. In other words, selectedAnswer is the entire object, not just the answer itself.
https://plnkr.co/edit/CRraZXY2jsmiV1oJx6VN?p=preview
$scope.profs = [
{ answer: 'answer2' }
]
$scope.availableAnswers = [
{ answer: 'answer1' },
{ answer: 'answer2' },
{ answer: 'answer3' },
];
angular.forEach($scope.availableAnswers, function(availableAnswer){
if ($scope.profs[0].answer === availableAnswer.answer)
$scope.selectedAnswer = availableAnswer
});
-- Old Answer --
Have you tried ng-init?
ng-init="selectedAnswer = profs[0].answer"
I have made a very complex plunkr, I was a bit slower than #brianslattery I guess.
Here's my take:
https://plnkr.co/edit/5fnB6oWrZ9WhujN7eH0T?p=preview
<section class="row" id="" ng-repeat="profile in profs">
<div class="col-xs-12" id="questionWidget">
<h4>{{configs[0].question}}</h4>
<!-- user's answer from db -->
Answer: {{profile.answer}}<br>
<select name="selector" ng-model="profile.answer" ng-change="selectedItemChanged(profile)" ng-options="a as a.answer for a in availableAnswers track by a.answer">
</select>
</div>
</section>
The app will look something like this:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($rootScope, $scope, $timeout, $log, $filter) {
$timeout(function() {
// get user's info from db and put it into scope
$scope.profs = [ { name: 'prof1', answer: 'a3' }, { name: 'prof2', answer: 'a2' } ];
$scope.buttonText = 'Update Profile';
appendAnswerObjects();
}, 100);
// get the configs from the configs service and put it in the rootScope
$timeout(function(data){
$rootScope.configs = [ { question: 'Question?', a1: 'a1', a2: 'a2', a3: 'a3', a4: 'a4', a5: 'a5' } ];
// get the answers from the config table for the select's options
$scope.availableAnswers = [
{ answer: $rootScope.configs[0].a1 },
{ answer: $rootScope.configs[0].a2 },
{ answer: $rootScope.configs[0].a3 },
{ answer: $rootScope.configs[0].a4 },
{ answer: $rootScope.configs[0].a5 }
];
appendAnswerObjects();
}, 200);
// function executed on change from the select
$scope.selectedItemChanged = function(profile) {
$log.log(profile);
}
function appendAnswerObjects() {
if($scope.profs && $scope.profs.length && $scope.availableAnswers && $scope.availableAnswers.length) {
$scope.profs.forEach(function(profile) {
profile.answer = $filter('filter')($scope.availableAnswers, { answer: profile.answer })[0];
});
}
}
});
There are several issues to consider. NgOptions likes to use objects rather than values. Also, your 'ng repeat' is calling for profs[0] instead of using the now repeated profiles variable.
Other issue to consider is that your 'answer' would not be 'profile dependent', but will be one for the entire scope, I'm pretty sure that is NOT what you want.
So, the plunkr I created makes individual answers for each. It also takes into account the possibility of getting either the profiles first or the available answers first, no matter which comes first, which is, I believe, Important.
Let me know if this helps.
Best regards,
Rafa.
I have <superhero> directive which has two directive
web-buttons to take of the form validation and post the updated
ngModel value to respective controller
fieldMap directive to generate the dynamic fields by object we are passing from respective controller
Here is the example which i have worked
directive attribute called saveFormFn will tell the button to call which function to invoked using enter attribute directive.
For example. After click save button it will call the function 'Ctrl1saveFormFn' from controller Ctrl1 .This function will make ajax post to save the form fields.
After updating the text fields with some content and click save,I have passed the current scope of the directive to respective controller (see console log). i could not get the updated fielddata value from current Scope.
$scope.Ctrl1saveFormFn = function(item){
_.each(item,function(currentScope){
console.log(currentScope)
// here i want to collect the form data with updated fielddata values
})
}
I am beginner.Am i on right path? Please advice
I've re-written your code because it was pretty hard to understand.
I would do it like this:
Use ng-include to load the template of your buttons. That's loading the control buttons edit and save.
Save your data in a variable in the superhero directive. Maybe it would be even better to store it in a separate service/factory.
Create a directive customForm that will create a form based on the supplied model that you're passing to its scope.
The main application logic is in the superhero directive because it is adding the controls save/edit to the DOM. If saving/editing is not only related to the superhero it would be better to do it in your main controller.
Please have a look at the demo below or in this jsfiddle.
angular.module('demoApp', [])
.directive('superhero', Superhero)
.directive('customForm', CustomForm)
.controller('mainController', MainController);
function Superhero() {
return {
restrict: 'E',
scope: {
formModel: "=",
},
template: '<div class="hero"><div ng-include="\'web-buttons.html\'"></div><custom-form model="formModel"></custom-form></div>',
controllerAs: 'superHeroCtrl',
controller: function ($scope) {
var self = this;
console.log('controller directive');
angular.extend(this, {
abilities: [],
editMode: false,
addStrength: function (data) {
self.abilities.push(data);
},
getStrength: function () {
return self.abilities;
},
showSave: function() {
self.editMode = true;
$scope.formModel.editMode = true;
},
hideSave: function() {
self.editMode = false;
$scope.formModel.editMode = false;
},
save: function() {
self.addStrength('can fly');
console.log(self.getStrength());
console.log('saving data now of form now...', $scope.formModel.data);
alert('saving data of form now: ' + self.getStrength()[0] + ' - ' + JSON.stringify( $scope.formModel.data, null, 2));
self.hideSave();
}
});
}
}
}
function CustomForm() {
return {
restrict: 'EA',
scope: {
model: '='
},
template: '<div ng-if="model.editMode" ng-repeat="formElement in model.fields" ng-include="formElement.template.url"></div>'
}
}
function MainController() {
this.normalForm = {
editMode: false,
data: {
},
fields: {
'NAME':{
template: {
url: 'customForms/text.html',
type: 'edit' // not sure for what it is needed
},
label: 'First name',
id: "NAME",
placeholder : "First Name",
fieldData: "NAME",
key : 'first_name'
},
'LNAME': {
template: {
url: 'customForms/text.html',
type: 'edit' // not sure for what it is needed
},
label: "Last Name",
placeholder : "Last Name",
id: "LNAME",
key : 'last_name'
}
}
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController as mainCtrl">
<script type="text/ng-template" id="customForms/text.html">
<label for="{{formElement.id}}">{{formElement.label}}</label>
<input ng-model="model.data[formElement.key]" placeholder="{{formElement.placeholder}}" id="formElement.id"/>
</script>
<script type="text/ng-template" id="web-buttons.html">
<button ng-click="superHeroCtrl.showSave()" ng-if="!superHeroCtrl.editMode">edit</button>
<button ng-if="superHeroCtrl.editMode" ng-click="superHeroCtrl.save()">save</button>
</script>
<superhero form-model="mainCtrl.normalForm"></superhero>
<h3>debug output:</h3>
<pre>
{{mainCtrl.normalForm |json}}
</pre>
</div>
I have problem with updating view by using ng-repeat.
When click on text, it doesnt update but it overwrites below. (I want have panel with names(links) and show its description on view)
I have searched everything and couldnt find answer or something useful what would help me.
html:
<body>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<ul>
<li><a ng-repeat="item in items" ng-click="getInfo(item)" > {{item.name}} <br> </a></li>
</ul>
</div>
<hr>
<div ng-controller="myInfo">
<div ng-repeat="info in item" >
<h3>Name: {{info.name}}</h3>
<p> ID: {{info._id}}</p>
<p> temp: {{info.temp}} </p>
</div>
</div>
</div>
</body>
js
var app = angular.module('myApp', [])
app.controller('myCtrl', function($scope, $http, shareDataService) {
$http.jsonp('data.json').success(function(data) {
$scope.items = data;
});
$scope.getInfo = function(item) {
shareDataService.addItem(item);
}
});
app.controller('myInfo', function( $scope, shareDataService ){
$scope.item = shareDataService.getItem();
});
app.service('shareDataService', function() {
var myItem = [];
var addItem = function(newObj) {
myItem.push(newObj);
}
var getItem = function(){
return myItem;
}
return {
addItem: addItem,
getItem: getItem
};
});
json
angular.callbacks._0([
{
"_id": 1,
"temp": "asdgdf",
"name": "name1"
},
{
"_id": 2,
"temp": "asdasdasd",
"name": "name2"
},
{
"_id": 3,
"temp": "asasdasdadgdf",
"name": "name3"
}
]);
Plunker: http://plnkr.co/edit/X65oH0yAkRnN8npKnFY2?p=preview
You have an error in your console. Just add track by to your ng-repeat:
<div ng-repeat="info in item track by $index">
ng-repeat needs a unique id to track the items in order to be able to update them. If you add the same item twice, ng-repeat sees the same item twice, ans loses its mind. Using $index (which is unique) resolves that issue.
Keep in mind that using $index is adequate here, but it's preferred to use a unique id from the object if you can.
EDIT:
If your issue is that you want to see only the one element you clicked on in your view, then the issue is that you are adding your item to an array, when you should just be setting a value in your service. And, obviously, no need of a ng-repeat in your view.
http://plnkr.co/edit/Wfg9KhCWKMDreTFtirhR?p=preview
JS:
app.controller('myCtrl', function($scope, $http, shareDataService) {
//[...]
$scope.getInfo = function(item) {
shareDataService.setItem(item);
}
});
app.controller('myInfo', function( $scope, shareDataService ){
$scope.$watch(function () {
return shareDataService.getItem();
}, function (value) {
$scope.info = value;
})
});
app.service('shareDataService', function() {
var myItem;
return {
setItem: function(newObj) {
myItem = newObj;
},
getItem: function(){
return myItem;
}
};
});
HTML:
<div ng-controller="myInfo" ng-show="info">
<h3>Name: {{info.name}}</h3>
<p> ID: {{info._id}}</p>
<p> temp: {{info.temp}} </p>
</div>
If you only want to display information of the item that you just have clicked, then we don't need the second ng-repeat (as jlowcs said).
We also don't have to defined myItem as a array, it's just unnecessary, I think.
Edit:
how embarrassing i am, my answer look exactly to same as jlowcs's. I guess I took to much time to figure out the answer.
One thing to add up:
Why do I need a $watch in myInfo controller?
Because at the first time, we use ng-repeat, this component do the watch part for us. Then when I remove ng-repeat, I need to watch for data changing by myself.
I have such json representation of a post by its id:
http://127.0.0.1:8000/update/1?format=json
{"title": "about me", "content": "I like program", "created": "2014-11-29T18:07:18.173Z", "rating": 1, "id": 1}
I try to update rating by button click:
<button ng-click="click(post.id)">Click me</button>
I have such javascript code:
<script>
var demoApp = angular.module('demoApp',['ngResource']);
demoApp.controller( 'AllPosts', function ($scope, $http)
{
$http.get('/blogpost/?format=json').success(function(data,status,headers,config)
{
$scope.posts = data.results;
$scope.predicate = '-title';
$scope.click = function(post_id, $resource){
var Post = $resource('/update/:PostId ',{PostId:post_id,format:'json'} );
post = Post.get({PostId:post_id}, function() {
post.rating = post.rating+ 1 ;
post.$save();
});
};
}).error(function(data,status,headers,config)
{} )
;})
</script>
Peharps i have mistake because in json i have a single object. But i dont really know
Besides i have such view to have a json by certain post by its id:
class UpdateModel(generics.RetrieveUpdateDestroyAPIView):
lookup_field = 'id'
queryset = BlogPost.objects.all()
serializer_class = BlogPostSerializer
permission_classes = (AllowAny,)
A quick tidy up of your script tag shows that you are only defining the function click if the http call was successful.
I would suggest moving the definition of the click method outside of the success callback.
You may also be running into a race condition that the click function has not been defined before clicking the actual button. Regardless you will want to move that function definition to where the controller is actually created.
Suggested edits (moved click definition outside of http call response):
var demoApp = angular.module('demoApp', ['ngResource']);
demoApp.controller('AllPosts', function($scope, $http, $resource) {
$scope.click = function(post_id) {
var Post = $resource('/update/:PostId ', {
PostId: post_id,
salutation: 'json'
});
post = Post.get({
PostId: post_id
}, function() {
post.rating = post.rating + 1;
post.$save();
});
};
$http.get('/blogpost/?format=json').success(function(data, status, headers, config) {
$scope.posts = data.results;
$scope.predicate = '-title';
}).error(function(data, status, headers, config) {});
})
Updates:
Injected $resource into the controller
Removed $resource from click function params
I am building an app with Angular.js accesing the LinkedIn API. What happens is that when I do a call to the API, the model does not get refreshed inmediately, but after I do another change on the screen. For example, I have binded the API call to a button, but I have to press it twice for the screen to get the data refreshed. This is my controller:
angbootApp.controller('AppCtrl', function AppCtrl($scope, $http) {
$scope.getCommitData = function() {
IN.API.Profile("me").fields(
[ "id", "firstName", "lastName", "pictureUrl",
"publicProfileUrl" ]).result(function(result) {
//set the model
$scope.jsondata = result.values[0];
}).error(function(err) {
$scope.error = err;
});
};
});
And this is my button and a link with the content:
<div>
{{jsondata.firstName}}
<form ng-submit="getCommitData()">
<input type="submit" value="Get Data">
</form>
</div>
EDIT: Explanation on how I did it here
You need to call $scope.$apply when retrieving the results/error
angbootApp.controller('AppCtrl', function AppCtrl($scope, $http) {
$scope.getCommitData = function() {
IN.API.Profile("me").fields(
[ "id", "firstName", "lastName", "pictureUrl",
"publicProfileUrl" ]).result(function(result) {
//set the model
$scope.$apply(function() {
$scope.jsondata = result.values[0];
});
}).error(function(err) {
$scope.$apply(function() {
$scope.error = err;
});
});
};
});
Anything outside angular world does not trigger automatic refresh of the views.
See $apply