Nested view controller and ng-click - AngularJs - javascript

I have 8 jade view that only one of them is loaded at the time and is filled by jquery into a div which has a controller.
Now, I have 2 question about these:
Does it necessary to define again the controller on top of my partial view(same controller with main controller) ?
All of these views has same ng-click. but after loading they doesn't work. However they work by jquery click event. Should I do any extra thing with them?
I had same problem with li element before, but I resolve it by getting help from ng-click not working from dynamically generated HTML by using compileData but I can't get result with button.
Code:
Main jade:
div(ng-controller="elementCtrl")
div#ddd(class="col-lg-7 col-md-5 col-sm-7")
Partial view sample:
div#spPartial()
div.col-lg-12.col-md-12.col-sm-12
span.col-lg-2.col-md-5.col-sm-5 Name
input#EnglishName(name="name" type="text" ng-model="elementModel.Name" value="#{Name}" class="col-lg-5 col-md-7 col-sm-5")
button(type="button" compile-Data name="btnSaveElement" ng-click="saveElement()") Save
Main part of controller:
//It loads the partial view - It works successfully
$http.post('/api/elements/getElementTypesPartial',
{
"ElementId": elementId,
"ProgramId": newVal,
"ElementTypeId": elementTypeId
})
.success(function (d2) {
$("#ddd").html(d2);
}
//It doesn't work at all
$scope.saveElement = function () {
alert();
alert($scope.elementId);
}
And one additional thing is that I put $scope.saveElement in root of controller scope. I don't have any idea about how angularJs manage $scope, So I see $scope.elementId in client code. Is it right or I should regenerate it($scope.saveElement) every time that partial is loaded?
Sorry I couldn't find any reference which describes these...

You should get rid of the jQuery loading and use an angular router which will load templates based on route configuration.
Since they are loaded by angular, it does all the compiling for you.
The router takes care of the ajax to get the templates automatically also.
Controllers also get defined in the routing config so you would be able to remove ng-controller from the templates
The change over shouldn't take long since setting up routing config is fairly easy to get it started
This would clear up the ng-click problems

Related

Angular js plunkr not working while accessing through iframe

i am not able to access Model for model in below plunkr, please find plunkr below.please help.
<div ng-controller="PersonCtrl">
<h2>Teens - using external HTML file as template</h2>
<iframe src="teen-external.html"></iframe>
</div>
Here's the Plunkr for any ref.
You have a couple of problems in your example, first the html source was loaded in iframe, which loads it as a simple html and renders it inside the iframe without angular parsing it to do all the mastache interpolation.
To correct this since you've already created a directive that renders the teen-external.html which would allow angular to parse the said html and interpolate the relevant fields. to do this simply use the directive inside your index.html file like.
<teen-internal> </teen-internal>
or
<div teen-internal></div>
Another problem is that you're trying to access a variable/model defined inside the parents $scope which is not possible without going via the $scope.$parent. Even if you do it using the $parent it is considered a really bad practice. To this a bit more elegantly angular provides a sort of model/variable passing from parent to the child, to do this you need to change both the index.html and the teensInternal directive code.
in your index.html
or
<div teens-internal teens="teens"></div>
This sets the teens property on the teensInternal's $scope to the teens from the parent's(PersonCtrl) $scope. Now in your directive code you must define how the binding works for teens property, here you can define it as a read only # also called one way binding (modification done inside teensInternal is not reflected inside the parent controller) or as writable = two way binding (both teensInternal and PersonCtrl share the same object, so the modifications are reflected in both sides) to do this change
scope: {
},
to
scope: {
teens: '=' // or "#" for one way binding
},
This tells the directive that whatever was passed to <teens-internal teens="teens"></teens-internal> through teens="<model's name>" can be used inside the directive's $scope.
Plunkr: plunkr source

Custom directive tag not triggering directive code, in angularjs 1.2.29

I'm trying to use an element directive (restrict: "E") to define a custom component. Here's my page.html template, which gets pulled into index.html via the ng-view directive:
<eng-popup>This text appears, but is rendered in a span</eng-popup>
Angular IS running; index.html has the ng-app="templatesApp" directive in the body tag and app.js sets up the module as below:
var app = angular.module("templatesApp", ['ngRoute']);
Further along, in app.js I have the popup directive defined:
app.directive('engPopup', function() {
console.log("This console log does not trigger. I have tried 'eng-popup' as the directive's first parameter, but that doesn't work either.");
return {
restrict: 'E',
transclude: false,
template: '<div id="thisDoesNotEvenAppear"></div>'
};
});
The problem is, when I look at the resultant html of the component, it looks like this:
<span class="ng-scope" jQuery110209261664696867675="7">This text should appear, surely</span>
</eng-popup class="ng-scope" jQuery110209261664696867675="8"><//eng-popup>
So I have a few questions:
Why does the eng-popup directive console.log call NOT get triggered?
Why does the content in the eng-popup tag end up in a span?
And most mysteriously of all, why does the eng-popup tag start with an END tag and end with a tag with 2 slashes?
Finally, what am I messing up, to make this all happen?
EDIT
As requested, here's a Plunker. It looks like the span and end-tag issues are not happening in this simplified version, but the eng-popup directive is still not being triggered:
https://plnkr.co/edit/mVa6Mye5besJAtWihMWF?p=preview
RE-EDIT
Just in case this is still solvable, here's the latest Plunkr I've been able to put together. It's not working, which it at least has in common with our real project. Not sure if it's the same problem though.
https://plnkr.co/edit/sJoYnYjqx9ZGIH0KhObC
I've modified your example a bit (very little), and it seems to work OK?
https://plnkr.co/edit/3NlHNDOCBVRktk3ZcsnV?p=preview
What i've done is, remove the ui-router requirement, since you had not added the script reference. After that, it works. So, are you including ui-router in your project properly?
So a colleague has pointed out it 'works' in Chrome. Turns out it's an IE8 issue. Who would have thought...
(The whole reason we're using 1.2.29 is because many of our users will be accessing it via IE8, but it looks like custom directives are off the table).

Angularjs: is this the right place to use a directive?

I've recently switched from jQuery to Angularjs and I am in the process of re-coding some pagination logic for the links ("Next", "Previous", etc.) that were written in jQuery-style Javascript previously.
Each link has an ngIf condition (for example, the "Previous" link won't show if you're on page 1) plus an ngClick event, which essentially updates a scope variable called $scope.pagination.position that determines which results are displayed in the table.
My original code was something like this (simplified for clarity):
Template
<a ng-if="pagination.position > 0" ng-click="pagination.first()">First</a>
Controller
$scope.pagination = {
first: function() {
this.position = 0;
}
}
Then I learned more about directives, and how most DOM elements that aren't static HTML should be created using a directive. So I switched each link (since each has it's own display rules and behaviour on clicks) to its own directive, like so:
Template
<a pagination-first></a>
Directive
app.directive('paginationFirst', function() {
return {
link: function(scope,el,attr) {
scope.pagination.first = function() {
scope.pagination.position = 0;
}
},
replace: true,
template: '<a pagination-first ng-if="pagination.position > 0" ng-click="pagination.first()">First</a>'
}
});
I'll cut straight to the chase : am I doing directives wrong? All that's happened, from my perspective, is I've flipped from having logic in my template to having a template in my logic, and I've defined the click event function in the directive rather than in the controller.
Is this even an appropriate time to be using a directive?
I'd like to learn best practices, so I'd love to know if I've missed the point and if the original templated-based ngIf and controller function approach was fine, even with longer and more complex ngIf conditions than the one shown.
If I want to add specific behaviors to a dom or dom list then I normally create a directive. As per angular js perspective the dom manipulation should only be done through directive (For me it is the best place, sometime I have to disobey this due to my lack of knowledge ). I specially found directive use full while creating a widget. In one of my project there was a part where a section is dedicated to display an image and also upload the image. I just use the directive on the top div, with the help of link function I attached the event handlers to various child dom. And as my project doesnot require an isolated scope (as this widget was all used in a single project and the outer scope was under my control) . So it worked like a charm. I cerarted the directive once. And used that widget through rest of the project as it's behavior and design (of the widget ) was same through out the project. For the pagination widget you can create a directive. Take the directive attibutes value as the input of the pagination parameters. Like calling script, limit offset. Container identifier to update the content. Then you can solely concentrate on the pagianation behavior. But from my experience (as I am also not so experienced in angular js), sometimes it becomes a little hectic to develop a directive and and use that throughout the project. As in some places we need to modify the behavior of the directive. And for this it may breaks elsewhere. But I know as I learn more I will be more efficient to handle this kind of situation. Hope my experience will help you.

AngularJS : Load additional template in custom directive

I have an Angular custom directive which uses a very simple carousel template which only has 2 slides loaded and bound because I expect to repeat lots of them on a page. When the user interacts with the directive I want to load an additional template containing the rest of the slides and compile it under the same scope as everything else in the directive.
This is how I am doing it so far. This function is inside my directive and is called when the user clicks the "next" button.
function loadExtraSlides(){
$templateRequest('/templates/propertyCardExtraSlides.tpl.html').then(function(template) {
$compile($(carouselEl).append(template).contents())($scope);
// Template is loaded
}, function() {
$log.error('Error loading card slides template');
});
}
}
}
This seemed to work at first because the template is loaded and inserted inside the carousel, but unfortunately the new template isn't bound to the scope correctly. If I put {{images}} into the main template is outputs an array of image URLs from my directive's scope. If I put the same thing in my template which is being imported and compiled it just outputs "{{images}}" to the DOM.
Hopefully I'm doing something simple wrong. Any help would be really appreciated.

AngularJS : Re-use controller functions and templates in different controllers

The title is a big ambigious, but this is the problem.
Assuming I am working in AngularJS and I have several views that largely need the same logic.
Code overview
app.js
$routeProvider
.when('/sheet/:sheetid/:screenid', {
templateUrl: 'views/sheet.html',
name: 'sheets',
controller: 'SheetCtrl'
});
index.html
<div class="container" ng-view></div>
The shared controller
Now this is the part where it all falls down in my mind. I need this controller to work on all 10 sheets. Right now I'm loading the data/model for the sheet through a service, which is working for now. The thing is though, that every sheetid shares a lot of code, but they can also differ from one another.
For instance:
sharedController.js
angular.module('App')
.controller('SheetCtrl', function ($scope, $routeParams, sheets) {
$scope.sheetid = $routeParams.sheetid;
/** GET THE SHEET */
//Gets the correct model from the sheets service (via promise)
$scope.sheetData = sheets.getSheet($scope.sheetId);
/** FACTSHEET SPECIFIC LOGIC */
//TODO: Figure out how to load specific factsheet controls in here
/* THE LOGIC FOR ALL THE SCREENS. WE NEED THIS AT ALL TIMES */
$scope.setScreen = function(index) {
...
};
//there are some more functions here that need to be shared
});
The view is a problem too
Every sheet has to be parsed in the same template. The problem is though that even these templates can differ tiny bits, and only from one div nested in this template. I would want to assign sheetID specific controller logic to the sheet-content, and also give the sheet-content it's own template/view.
<div class="sheet">
<div>
close
</div>
<div class="sheet-content">
<!-- Assume sheet specific controller code to target this div-->
</div>
</div>
Now what?
Not quite sure how to continue from here. It seems like I should be able to somehow dynamically assign controller logic for specific sheetID's to the sheet-content div and assign a template here. I'm really looking for the method to do this as clean and DRY as possible.
For instance, I could copy/paste the view and sharedController 10 times and assign them to every possible path, but I really do not want to repeat myself.
Another problem is that every factsheet should build his own model somehow. Right now I am doing it through a service with predefined data, but it would be cleanest if the specific controllers are handling that. The problem is when I put that logic in the specific controllers, the sharedControllers can't use that model anymore and won't build again.
If anyone could point me in the right direction I'd be very happy about that.
Partials loaded inside the parent inherit parent controller:
<div ng-controller="SheetCtrl" class="container" ng-view></div>
Here's what I eventually did. I included a view in the sheet-content according to a $scopevariable. I created 10 different views. In these 10 views I only changed the ng-controller element. All these views then ng-include another view which is shared across all 10 controllers.
I'm not totally happy about loading the data for the sheet in the sheet.js controller, but for now it seems the most DRY method of working. If I can think of a way to load this data in the corresponding sheet controller I'd rather do that.
sheet.js
This controls all of the sheets, contains shared functions and loads the data
$scope.template = {
url: '/views/sheets/sheet' + $scope.sheetid + '.html'
};
sheet.html
This view simply loads the template provided above, looking at the sheetid
<div ng-include="template.url">
sheet1.html (goes on to sheet10.html)
Simply assigns the right controller so I can seperate my code
<div ng-controller="Sheet1Ctrl">
<div ng-include="'views/sheets/sheet-wrapper.html'"></div>
</div><!--controller-->
sheet-wrapper.html
This view is shared across all sheets. Changing this view changes all the sheets
<div class="mpj-factsheet-dynamic"></div>

Categories