Reset data on click for a different controller - javascript

I have two divs - the first contains the second. The contained div has its own controller. When I click an icon button in the container, I change a variable which then affects the visibility of the contained div.
It looks like this:
<div ng-controller="BarController">
<div class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<div class="col-lg-2 page-title">My Page</div>
<div class="col-lg-10">
<span class="actions">
<i class="fa fa-lg fa-download fa-inverse" tooltip="Download"
ng-click="showSecondaryBar=!showSecondaryBar"></i>
</span>
</div>
</div>
</div>
<div class="download navbar download-in download-out"
ng-class="{'myhidden': !showSecondaryBar}"
ng-cloak>
<div class="col-lg-offset-4 col-lg-4 form-inline form-group" ng-controller="TagsController">
<div class="download-label col-lg-6">
<label>Download by tags:</label>
</div>
<div class="download-tags col-lg-6">
<tags-input class="bootstrap" spellcheck="false" min-length="1" ng-model="tags" add-from-autocomplete-only="true">
<auto-complete source="loadTags($query)" min-length="1" load-on-down-arrow="true"
load-on-focus="true" max-results-to-show="5"
highlight-matched-text="false"></auto-complete>
</tags-input>
</div>
</div>
</div>
</div>
The <tags-input> is taken from ng-tags-input and I would like to reset the tags that were already typed to it whenever the icon button is clicked (which changes the visilibyt of the div that contains the ng-tags-input).
Problem is, because I have the TagsController which contains the data (tags) and this data is not visible in the BarController, I'm not sure how I can reset the tags array to become empty.
I thought of using a service but it fills like too much of a coupling. I would prefer to have a function in TagsController which is called upon click. But I can't figure out how to do it from another controller

You are right you have to use a service.
Why don't you use a broadcast as your TagsController is included in BarController?
You can include a scope.broadcast("Event") in BarController
Then a "on" listener on TagsController who will reset the tags array when "Event" Occur.
I would personnaly to this.
https://docs.angularjs.org/api/ng/type/$rootScope.Scope

You can use $broadcast on $rootScope to send an event to TagsController. So TagsController can receive this event by registering an event listener for it. See following example.
Refer to $rootScope API docs
angular.module('app',[])
.controller('ParentController', function($rootScope) {
var parentCtrl = this;
parentCtrl.someFlag = true;
parentCtrl.changeFlag = function() {
parentCtrl.someFlag = !parentCtrl.somFlag;
$rootScope.$broadcast('resettags', {'defaultTags': 'whatever_tag'});
}
})
.controller('ChildController', function($rootScope){
var childCtrl = this;
childCtrl.tags = "Some tags entered by user";
$rootScope.$on('resettags', function(event, args) {
childCtrl.tags = args.defaultTags;
});
});
.myHidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div id="main" ng-controller="ParentController as parentCtrl">
<button type="button" ng-click="parentCtrl.changeFlag()">Toggle</button>
<div ng-class="{'myHidden' : !parentCtrl.someFlag}">
<div ng-controller="ChildController as childCtrl">
<h1>{{childCtrl.tags}}</h1>
</div>
</div>
</div>
</div>

Related

Reuse html template in Angular project

I have this html template file, range-details-dialog.tpl.html
<div class="modal-header clearfix text-left">
<h5>Update Range</h5>
</div>
<div class="modal-body">
<form name="form" role="form" class="ng-pristine ng-valid" novalidate ng-submit="updateRange()">
<div class="form-group-attached">
<div class="row">
<div class="col-sm-12">
<div class="form-group form-group-default input-group p-l-10 p-r-10" ng-class="{ 'has-error' : form.$invalid }">
<p ng-show="form.rangeDaily.$error.min" class="help-block">Daily range more than £5</p>
</div>
</div>
</div>
</div>
</form>
<div class="row">
<div class="col-sm-8"></div>
<div class="col-sm-4 m-t-10 sm-m-t-10">
<button type="button" class="btn btn-primary btn-block m-t-5"
ng-disabled="form.$invalid || promise" promise-btn="promise" ng-click="updateRange()">Update</button>
</div>
</div>
</div>
Then I want to have another file forced-range-details-dialog.tpl.html
These two files could be one file instead with dynamically populated placeholders.
These are the places were substitution would be needed:
<h5>Update Range</h5> would become <h5>Update Forced Range</h5>
<p ng-show="form.rangeDaily.$error.min" class="help-block">Daily range more than £5</p>
would become:
<p ng-show="form.forcedRangeDaily.$error.min" class="help-block">Forced Daily range more than £5</p>
ng-disabled="form.$invalid || promise" promise-btn="promise" ng-click="updateRange()">Update</button>
, ng-disabled="form.$invalid || promise" promise-btn="promise" ng-click="updateForcedRange()">Update</button>
Is there a way to avoid having two separate template files for the above? Could you please provide some examples, links, or pointers as to how that can be achieved?
Also, I see in the answers that a solution would be to add a boolean parameter inside the component and then call it twice. I am not sure how to call the component though. I have pasted my component below:
angular.module('app.investment.rangeDetails')
.component('pxForcedLimitAmount', {
templateUrl: '/assets/js/apps/range/range-details-dialog.tpl.html',
bindings: {
amount: '<',
isRequest: '<?',
requestedAt: '<?',
#Input() isForced: boolean //<<----I added this based on answers below
},
controller: [function () {
var ctrl = this;
ctrl.$onInit = function () {
ctrl.isRequest = ctrl.isRequest === true || false;
};
}],
});
Seems like only the placeholders need to change, so you can use a variable to decide what placeholder to display on the template. For example:
isForced: boolean;
ngOnInit() {
this.isForced = true; // decide how you want to toggle this
}
on the template:
<h5 *ngIf="!isForced">Update Range</h5>
<h5 *ngIf="isForced">Update Forced Range</h5>
and
<p *ngIf="!isForced" ng-show="form.rangeDaily.$error.min" class="help-block">
Daily range more than £5</p>
<p *ngIf="isForced" ng-show="form.forcedRangeDaily.$error.min" class="help-block">
Forced Daily range more than £5</p>
you can do the same for other tags as well.
From the comments, one way to "determine" the value for isForced is to introduce an input property to the component i.e.
#Input() isForced: boolean;
and invoke the component from elsewhere like:
<app-user [isForced]="true"></app-user>
You can use inputs.Write a component which takes input, and render it in html. then call this component in desired places with its selector
For events use output
See the doc https://angular.io/guide/inputs-outputs

How do I adjust marquee based on global variable? - Meteor

I'm developing an app using Meteor Framework.
One of the features I am looking to implement is having a marquee text (like a scrolling bottom text).
I have added the package meteor-jquery-marquee and it works great with a single string. But whenever I try to modify the string, nothing happens, and it stays the same.
It's worth mentioning that I did try sessions, and it changes the text, however, the marquee animation stops, which defeats the purpose.
I have been stuck for hours trying to get it to work, some help would really save my butt here.
I've initialized the global variable in the client/main.js as
globalMessage = "Welcome to my proJECT";
And it scrolls with the marquee just fine.
Thank you in advance!
My code:
My body template
<template name="App_Body">
{{> Header}}
{{>Template.dynamic template=main}}
{{> Footer}}
<div style="color: white;" class="ui center aligned container">
<div class='marquee'>{{globalMessage}}</div>
</div>
</template>
body.js
Template.App_Body.helpers({
globalMessage () {
return globalMessage;
},
});
where I'm trying to edit the marquee:
<template name="dailyMessageControl">
<div class="container">
<br>
<br>
<div class="info pull-right"> <!-- column div -->
<div class="panel panel-default">
<div class="panel-heading clearfix">
<h1 class="panel-title text-center panel-relative"> Modify Daily Message</h1>
</div>
<div class="list-group">
<div class="list-group-item">
<p style="font-size: 30px;">Current Message: <br>{{globalMessage}}</p>
</div>
<div class="panel-footer">
<form>
<div class="form-group">
<label for="exampleInputEmail1">Enter new messages</label>
<input type="text" name="newMsg" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="New Message">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</div><!-- end column div -->
</div>
</template>
the .js
Template.dailyMessageControl.helpers({
globalMessage () {
return globalMessage;
},
});
Template.dailyMessageControl.events({
'submit form': function(){
event.preventDefault();
var newMsg = event.target.newMsg.value;
globalMessage = newMsg;
}
});
Your code clearly lacks reactivity, let's fix that.
Fist, initialize globalMessage as ReactiveVar instance (client/main.js):
globalMessage = new ReactiveVar('Welcome to my proJECT');
Next, code to react to its value change (body.js):
Remove globalMessage() helper
Add code that will track globalMessage variable and re-create $.marquee:
Template.App_Body.onRendered(function appBodyOnRendered() {
this.autorun(() => {
const value = globalMessage.get();
const $marquee = this.$('.marquee');
$marquee.marquee('destroy');
$marquee.html(value);
$marquee.marquee(); // add your marquee init options here
});
});
And, lastly, update code in dailyMessageControl template to work with ReactiveVar instance:
Template.dailyMessageControl.helpers({
globalMessage () {
return globalMessage.get(); // changed line
},
});
Template.dailyMessageControl.events({
'submit form': function(){
event.preventDefault();
var newMsg = event.target.newMsg.value;
globalMessage.set(newMsg); // changed line
}
});

My single page application which is implemented using AngularJS is taking long time to load the page

I am working on the Single page application and using AngularJS. In my application, all DOM elements get loads using ajax and due to this I have used number of ng-repeat and binding expression and this is the reason my page is taking long time to load the page. Please help to solve my issue.
app
angular.module('tabApp', []);
Service
angular.module('tabApp')
.service('mrcService', ['$http', function($http) {
this.categories = [];
this.getCategories = function() {
return $http({
method: "GET",
url: 'mrcdata.aspx'
}).success(function(data) {
categories = data;
return categories;
});
};
}]);
Controller
angular.module('tabApp')
.controller('dynamicContentCtrl', ['$scope', 'mrcService', function($scope, mrcService) {
$scope.categories = [];
mrcService.getCategories().then(function(response) {
$scope.categories = response.data.Categories;
});
}]);
HTML code
<div class="main-content container" ng-controller="dynamicContentCtrl">
<div ng-controller="desktopTabCtrl" class="row desktop-content">
<div class="col-md-3 col-sm-4 category-items">
<nav class="nav categories-nav">
<ul class="categories">
<li ng-repeat="category in categories" class="category" ng-class="{ active: isSet(category.CategoryRank) }">
<a href="javascript:void(0)" ng-click="setTab(category.CategoryRank)" class="text">
<span>{{category.CategoryTitle}}</span>
</a>
<span class="arrow-right"></span>
</li>
<li class="category static">
<C5:LocalLiteral runat="server" Text="mrc.home.learnmoretab"/>
</li>
</ul>
</nav>
</div>
<div class="col-md-9 col-sm-8 document-tiles">
<div ng-repeat="category in categories" ng-show="isSet(category.CategoryRank)" class="tile-container">
<div class="row">
<div ng-repeat="document in category.Documents" class="col-md-6 col-sm-6 tile">
<div class="tile-content row">
<div class="col-md-12 col-sm-12">
<div class="thumbNail-content col-md-6 col-sm-6">
<p class="title">{{document.DocumentTitle}}</p>
<p class="audience">{{document.Audience}}</p>
</div>
<div class="thumbNail-image col-md-6 col-sm-6">
<img alt="Thumb Nail" src="{{document.ThumbnailUrl}}">
</div>
</div>
<div class="col-md-12 col-sm-12">
<div class="download-section">
<select class="lang-dropdwn"
ng-model="document.DefaultDialectId"
ng-change="selectLang(document , document.LocalizedDocuments , document.DefaultDialectId )">
<option ng-repeat="localizedDocument in document.LocalizedDocuments"
value="{{localizedDocument.DialectId}}">
{{localizedDocument.LanguageName}}
</option>
</select>
</div>
<div class="button-conatiner" ng-init="document.DownloadLink = document.DocumentId +':'+document.DefaultLocalizedDocumentId">
<a class="button" href="documentdownloader.aspx?documentid={{document.DownloadLink}}"><C5:LocalLiteral runat="server" Text="basket.esddelivery"/></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Here's a few options you can try to improve performance.
1. You should set the track by in the ng-repeats
To minimize creation of DOM elements, ngRepeat uses a function to "keep track" of all items in the collection and their corresponding DOM elements. For example, if an item is added to the collection, ngRepeat will know that all other items already have DOM elements, and will not re-render them.
The default tracking function (which tracks items by their identity) does not allow duplicate items in arrays. This is because when there are duplicates, it is not possible to maintain a one-to-one mapping between collection items and DOM elements.
If you do need to repeat duplicate items, you can substitute the default tracking behavior with your own using the track by expression.
For example, you may track items by the index of each item in the collection, using the special scope property $index.
Example:
<div ng-repeat="item in items track by $index">{{item.name}}</div>
2. You could use one way data binding to items you know wont be changed. This will disable the watchers for those items and improve performance. Example:
Instead of this
{{item.name}}
Use this
{{::item.name}}
Please remember that this is a one way binding and these values will not be updated if something changes in your scope but you will need to manually update it.
3. Try to limit the ng-show and ng-hide attributes since this will add more watchers and leads to poor performance.

Angular Two Apps on the same page

What I am trying to do is render two Calendars on one page, each with a different data set. Currently the first Calendar loads correctly but the second calendar will not load. It doesn't appear to even try to load.
I am quite new to Angular, so I am not sure if what I am doing is allowed in the concept of a one page application, or if I should be doing it another way.
Open to all suggestions!
Calendar App Using: https://github.com/mattlewis92/angular-bootstrap-calendar
Front end (Trimmed down)
<div class="col-lg-9 panel panel-default" id="Calandars">
<button class="btn dropdown" data-toggle="collapse" data-target="#userCal" data-parent="#Calandars"><i class="icon-chevron-right"></i> User Calandar </button>
<button class="btn dropdown" data-toggle="collapse" data-target="#GlobalCal" data-parent="#Calandars"><i class="icon-chevron-right"></i> Global Calandar</button>
<div class="accordion-group">
<div id="userCal" class="collapse indent">
<!---User Calendar Configuration - Working Calendar-->
<div ng-app="UserCal" class="textfix">
<div ng-controller="Cal as vm">
<h2 class="text-center">{{ vm.calendarTitle }}</h2>
<mwl-calendar events="vm.events"
view="vm.calendarView"
view-title="vm.calendarTitle"
view-date="vm.viewDate"
on-event-click="vm.eventClicked(calendarEvent)"
on-event-times-changed="vm.eventTimesChanged(calendarEvent); calendarEvent.startsAt = calendarNewEventStart; calendarEvent.endsAt = calendarNewEventEnd"
edit-event-html="'<i class=\'glyphicon glyphicon-pencil\'></i>'"
delete-event-html="'<i class=\'glyphicon glyphicon-remove\'></i>'"
on-edit-event-click="vm.eventEdited(calendarEvent)"
on-delete-event-click="vm.eventDeleted(calendarEvent)"
cell-is-open="vm.isCellOpen"
day-view-start="06:00"
day-view-end="22:00"
day-view-split="30"
cell-modifier="vm.modifyCell(calendarCell)">
</mwl-calendar>
</div>
</div>
</div>
<div id="GlobalCal" class="collapse indent">
<!---Global Calandar Configuration -- None Working Calendar-->
<div ng-app="UserCal" class="textfix">
<div ng-controller="GlobalCalCon as vm">
<h2 class="text-center">{{ vm.calendarTitle }}</h2>
<mwl-calendar events="vm.events"
view="vm.calendarView"
view-title="vm.calendarTitle"
view-date="vm.viewDate"
on-event-click="vm.eventClicked(calendarEvent)"
on-event-times-changed="vm.eventTimesChanged(calendarEvent); calendarEvent.startsAt = calendarNewEventStart; calendarEvent.endsAt = calendarNewEventEnd"
edit-event-html="'<i class=\'glyphicon glyphicon-pencil\'></i>'"
delete-event-html="'<i class=\'glyphicon glyphicon-remove\'></i>'"
on-edit-event-click="vm.eventEdited(calendarEvent)"
on-delete-event-click="vm.eventDeleted(calendarEvent)"
cell-is-open="vm.isCellOpen"
day-view-start="06:00"
day-view-end="22:00"
day-view-split="30"
cell-modifier="vm.modifyCell(calendarCell)">
</mwl-calendar>
</div>
</div>
</div>
Javascript Behind
angular.module('UserCal', ['mwl.calendar', 'ui.bootstrap', 'ngAnimate'])
.controller('Cal', populateCal)
.controller('GlobalCalCon', populateGlobalCal);
function populateCal($http) {
Do Stuff
angular.copy(MyData, vm.events)
};
function populateGlobalCal($http) {
Do Diffrent Stuff
angular.copy(MyData, vm.events)
};
Well, In here you're using same module UserCal two times. This is your main SPA module so it will be only one time.
Please put ng-app="UserCal" to html/body tag and remove <div ng-app="UserCal" class="textfix"> from HTML code.
Now both the calender will work :)
cheers!
Its because you are using ng-app twice, you have to declare it only once on top of the page or best thing is declare it in ur index.html on html tag
On index.html:
<html ng-app="UserCal">
Or
On current page:
<div ng-app="UserCal">
<div ng-controller="Ctrl1">
// stuff goes herr
</div>
<div ng-controller="Ctrl1">
// stuff goes herr
</div>
</div>

How do I access ng-show directive with ng-click? AngularJS

I just started learning so I'm creating a todo app.
I'm trying to show a div when I click on the edit button to edit my task.
this is my html
<div ng-controller='TasksCtrl'>
<div ng-repeat='(key, task) in tasksList' class='task-list'>
<div class='easy'>
<div class='div-list-style'></div>
<div id='task-{{key}}' style='cursor:pointer;z-index:5'
ng-click='editTask()' data-key='{{key}}' class='options
pull-right glyphicon glyphicon-pencil'>
</div>
<div class='task-desc' ng-bind='task.description'></div>
<div ng-hide='taskEdit = true'>FORM</div>
</div>
</div>
</div
This is my controller
todoApp.controller('TasksCtrl',['$scope', 'saveTaskService', function($scope, saveTaskService){
$scope.editTask= function(){
todoApp.directive('taskEdit', function(){
return function(scope, element){
//so I guess over here I need do ngHide = 'false' ? //
alert(element.attr('data-key'));
};
});
};
}]);
Here is a quick solution, you have a scope variable called taskShow that will tell ng-hide when to show it, then on ng-click you will trigger a function that will toggle that value:
<div ng-controller='TasksCtrl'>
<div ng-repeat='(key, task) in tasksList' class='task-list'>
<div class='easy'>
<div class='div-list-style'></div>
<div id='task-{{key}}' style='cursor:pointer;z-index:5'
ng-click='toggleHide(key)' data-key='{{key}}' class='options
pull-right glyphicon glyphicon-pencil'>
</div>
<div class='task-desc' ng-bind='task.description'></div>
<div ng-show='taskShow[key]'>FORM</div>
</div>
</div>
</div>
Controller:
todoApp.controller('TasksCtrl',['$scope', 'saveTaskService', function($scope, saveTaskService){
$scope.taskShow = {};
$scope.toggleHide = function (key) {
$scope.taskShow[key] = !$scope.taskShow[key];
};
}]);
Edit: switched ng-hide to ng-show so the divs are hidden by default and only shown when the other is clicked.

Categories

Resources