angularjs: access inner scope from outer scope - scope

I am trying to move bits from a parent controller inside child controllers in an angularjs app to not pollute the main controller too much.
Here's a simplified fiddle: http://jsfiddle.net/terebentina/5RMPV/
So when I click the change button, the third letter should change to 'X'.
Initially the item_change() function was inside the main controller and was doing $scope.items[idx] = 'X' and this worked just fine. However, since I moved it inside the ItemCtrl, I have no idea how to access it for the 3rd element.
Any help would be much appreciated.

One way to move things out of your main controller is to share and make all changes to the data between controllers inside a service or factory (described pretty nicely in this article).
Here is an updated fiddle. You would just need to inject the itemsService into any controller you would want to access the items data in.
angular.module('test', [])
.service('itemsService', function(){
var items = ['A', 'B', 'C', 'D'];
return{
getItems: function(){
return items;
},
changeItem: function(index, value){
items[index] = value;
}
}
})
.controller('MainCtrl', function($scope, itemsService) {
$scope.items = itemsService.getItems();
$scope.change = function(idx) {
itemsService.changeItem(idx, 'X');
}
})

Related

AngularJS 1.5 component $postLink and data binding

I am building an Angular 1.5 component that wraps Chosen list, which needs to be initialized by calling .chosen() on the jQuery element. I can do that using the $postLink lifecycle callback, and something like $('.chosen-select').chosen(), which works fine. However, I can anticipate someone using multiple instances of the component on the same page, so using a class selector would not necessarily get the component you want.
I tried using an id selector instead, by adding a prefix to whatever id someone assigns to the component in HTML. For example, I may use the component like <chosen-select id="roles"></chosen-select> and in the template if have <select id="cs-{{$ctrl.id}}"> (in the controller, I bind id: '#'). This all works as expected EXCEPT that in $postLink, the select element has been created (and other bindings, such as the one that lists options, resolved) but id is still "cs-{{$ctrl.id}}". At what point does that become "cs-roles" (which is what it is in the DOM when everything has been set up)? What is the best way to ensure that I am accessing the object that belongs to this component?
Here is the component code, which works:
template:
<select id="cs-{{$ctrl.id}}" class="chosen-select"
ng-options="(option.name || option) for option in $ctrl.options track by (option.id || option)"
ng-model="$ctrl.result"
>
</select>
component:
mymod.component('chosenSelect', {
templateUrl: 'shared/components/chosenSelectComponent.html',
controller: chosenSelectController,
bindings: {
id: '#',
options: '<',
config: '<?',
selected: '<?',
doChange: '&?'
}
});
function chosenSelectController() {
var vm = this;
vm.result = vm.selected || vm.options[0];
vm.$postLink = function() {
// would like to use ("#cscomp-" + vm.id) to make sure it is unique,
// but id doesn't seem to have been resolved yet in select element
$(".chosen-select")
.chosen(vm.config)
.on('change', function(evt, params) {
// parms.selected also holds result
vm.doChange({ value: vm.result });
});
};
}
I realized I could use a hierarchical selector to solve the problem. In the $postLink function, referencing $("#" + vm.id + " .chosen-select") does exactly what I want it to by narrowing the selection to only elements that are descendants of the element with the specified id.

How to send some data of one template to another template Meteor

I want to share some data from template to another template using Meteor. I have a template i.e allInventory.html on which i am showing some data in table form i added three links there that is. one for view , edit and delete what i want iam getting all the data from backend into one of helper i.e productDetails and i bind an event with view button that will take the data of current user clicked on which product so i have successfully getting the data at my allinventory template but there is another template i.e productDetails on which i want to render or show that data. But stuck with that i have data on allInventory click event but not know how do ishare the same with productDetails template.
Here is my allInventory.js
Template.allInventory.rendered = function() {
Template.allInventory.events({
"click .btn":function (e){
data = $(e.target).attr('data');
Router.go('productDetail', {data: $(e.target).attr('data')}, {query: 'q=s', hash: 'hashFrag'});
console.log("button clicked.."+data);
console.log(data);
}
})
ProductDetails.js
Template.productDetail.rendered = function () {
Template.productDetail.helpers({
productDetails: function() {
return data;
}
});
allInvenrtory.html
<button type="button" data ="{{productInfo}}" class="btn btn-info btn-sm"><i class="fa fa-eye"></i>View</button>
I just simply want to share allInventory template data with productsDetails template.
Any help would be appriciated!
Thanks
I'd recommend avoiding Session for this purpose, since it is a global object, but more importantly, because there are better ways to do it.
You can pass data from the parent templates to the child template using helpers: https://guide.meteor.com/blaze.html#passing-template-content
You can pass data from the child to the parent templates using callbacks https://guide.meteor.com/blaze.html#pass-callbacks
I'd structure this app to have a container (page) template, which will have all the subscriptions and render one of your templates based on the URL.
You can use the Session variable if you want to share data between templates.
You can follow this guide:
http://meteortips.com/first-meteor-tutorial/sessions/
I would put both template in a third, parent template.
ParentTemplate
-SharedInfo
-KidTemplate1
-KidTemplate2
Then having this third template hold the information you want to share across templates.
For that you can use a ReactiveVar, ensuring that change by template1 code on the parent template is visible in template2 as well.
To access the parent template for the kids, you can do something along those lines :
Blaze.TemplateInstance.prototype.parentTemplate = function (levels) {
var view = Blaze.currentView;
if (typeof levels === "undefined") {
levels = 1;
}
while (view) {
if (view.name.substring(0, 9) === "Template." && !(levels--)) {
return view.templateInstance();
}
view = view.parentView;
}
};

Backbone.js: pass model to sub-view by reference

UPDATE: As it turns out, i had a leftover this.model = new MasterModel(); in my subViews initialize() function.
I am trying to separate my huge view to smaller views and so I have created a "master" layout view that attaches to itself some subviews and passes it's model to them.
However, it seems that when my sub-view updates the model, these changes are not reflected on the "master" view's model.
Here's what I am trying to do:
var master = new MasterModel();
var masterView = new MasterView({model:master});
Inside of the masterView initialize() function I do this:
function: initialize() {
this.subView = new subView({model:this.model});
}
And the code that changes the model in subView is this:
function: setCurrency() {
this.model.set({ currency: this.$('.currency').val() });
}
Maybe I am doing something completely wrong here?
How many things have class "currency" are on your page?
I don't think this.$('.currency').val() means what you think it means. I think you're wanting something like $(this.el).find('.currency').val() (are you using 0.9.1? then you could shorten that to $el.find('.currency').val() ). What you have will always grab the first item on the page with class "currency". this.$ is just a convenience reference to what would normally be the global Zepto or jQuery object. Hence, my question.
Edit: awaiting response to clarification question.
Make your model global so instead of:
var master = new MasterModel();
use
window.master = new MasterModel();
and then pas this to your subViews
function: initialize() {
this.subView = new subView({model:window.master});
}

Subclass QueryReadStore or ItemFileWriteStore to include write api and server side paging and sorting.

I am using Struts 2 and want to include an editable server side paging and sorting grid.
I need to sublclass the QueryReadStore to implement the write and notification APIs. I do not want to inlcude server side REST services so i do not want to use JsonRest store. Any idea how this can be done.? What methods do i have to override and exactly how. I have gone through many examples but i am not getting how this can be done exactly.
Also is it possible to just extend the ItemFileWriteStore and just override its methods to include server side pagination? If so then which methods do i need to override. Can i get an example about how this can be done?
Answer is ofc yes :)
But do you really need to subclass ItemFileWriteStore, does it not fit your needs? A short explaination of the .save() follows.
Clientside does modify / new / delete in the store and in turn those items are marked as dirty. While having dirty items, the store will keep references to those in a has, like so:
store._pending = { _deletedItems: [], _modifiedItems: [], _newItems: [] };
On call save() each of these should be looped, sending requests to server BUT, this does not happen if neither _saveEverything or _saveCustom is defined. WriteStore simply resets its client-side revert feature and saves in client-memory.
See source search "save: function"
Here is my implementation of a simple writeAPI, must be modified to use without its inbuilt validation:
OoCmS._storeAPI
In short, follow this boiler, given that you would have a CRUD pattern on server:
new ItemFileWriteStore( {
url: 'path/to/c**R**ud',
_saveCustom: function() {
for(var i in this._pending._newItems) if(this._pending._deletedItems.hasOwnProperty(i)) {
item = this._getItemByIdentity(i);
dxhr.post({ url: 'path/to/**C**rud', contents: { id:i }});
}
for(i in this._pending._modifiedItems) if(this._pending._deletedItems.hasOwnProperty(i)) {
item = this._getItemByIdentity(i);
dxhr.post({ url: 'path/to/cr**U**d', contents: { id:i }});
}
for(i in this._pending._deletedItems) if(this._pending._deletedItems.hasOwnProperty(i)) {
item = this._getItemByIdentity(i);
dxhr.post({ url: 'path/to/cru**D**', contents: { id:i }});
}
});
Now; as for paging, ItemFileWriteStore has the pagination in it from its superclass mixins.. You just need to call it with two setups, one being directly on store meaning server should only return a subset - or on a model with query capeabilities where server returns a full set.
var pageSize = 5, // lets say 5 items pr request
currentPage = 2; // note, starting on second page (with *one* being offset)
store.fetch({
onComplete: function(itemsReceived) { },
query: { foo: 'bar*' }, // optional filtering, server gets json urlencoded
count: pageSize, // server gets &count=pageSize
start: currentPage*pageSize-pageSize // server gets &start=offsetCalculation
});
quod erat demonstrandum

Kohana 3: How can I pass full control to another action within my controller?

In my controller, I have a before() function that calls parent::before() and then does some additional processing once the parent returns. based on a specific condition, I want to "save" the original request and pass execution to a specific action. Here is my before() function.
public function before() {
parent::before();
$this->uri = Request::Instance()->uri;
$match = ORM::factory('survey_tester')
->where('eid','=',$this->template->user->samaccountname)
->find();
if (!$match->loaded()) {
self::action_tester("add",$this->template->user);
}
}
And the action that is being called..
public function action_tester($op=null,$user=null) {
$testers = ORM::factory('survey_tester')->find_all();
$tester = array();
$this->template->title = 'Some new title';
$this->template->styles = array('assets/css/survey/survey.css' => 'screen');
$this->template->scripts = array('assets/js/survey/tester.js');
$tester['title'] = $this->template->title;
$tester['user'] = $this->template->user;
switch ($op) {
case "add":
$tester = ORM::factory('survey_tester');
$tester->name = $user->displayname;
$tester->email = $user->mail;
$tester->division = $user->division;
$tester->eid = $user->samaccountname;
if ($tester->save()) {
$this->template->content = new View('pages/survey/tester_add', $admin);
} else {
$this->template->content = new View('pages/survey/tester_error', $admin);
}
break;
default:
break;
}
}
This all seems to work fine. This is designed to prompt the user for a specific piece of information that is not provided by $user (populated by LDAP) if this is the first time they are hitting the controller for any reason.
The problem is the views are not rendering. Instead control passes back to whatever action was originally requested. This controller is called survey. If i browse to http://my.site.com/survey and login with new user info, the record gets written and i get the action_index views instead of my action_tester views.
I cannot figure out what I am doing wrong here. Any ideas will be appreciated. Thank you.
EDIT: I managed to get this working (sort-of) by using $this->request->action = 'tester'; but I'm not sure how to add/set new params for the request yet.
The issue is that you are calling your method (action_tester), but then Kohana is still going to call the original action after the before method is called, which is going to change the response content overwriting the changed made in action_tester().
You can change the action being called (after before is called) inside your before() method:
$this->request->action('action_tester');
After the before method is called, it should then call the new Action (action_tester) rather than the old one, but then you need to do something about the way you are passing your parameters then.
Or you could just redirect the request upon some condition:
if($something) {
$this->request->redirect('controller/tester');
}
This doesn't seem like a nice way to do it anyway.

Resources