ngDirective is not watching - javascript

I am trying to make angular works with semantic ui, specifically dropdown searching box. I have tried multiple things and I found that because the input type is set to be hidden, ng-model is not going to work. And because the change to the element is not directly triggered by the user, the ng-change also won't work.
My idea is to use a directive and try to monitor the input element's attribute, because after selecting something, the value attribute changes. I think ngDirective should be able to implement the ng-model and ng-change by using scope.$watch
I tried this but the scope value has not been changed.
var app = angular.module('myApp', [
'my.controllers'
]);
var controllers = angular.module('my.controllers', []);
controllers.controller('MyController', function($scope) {
$scope.checked = true;
});
app.directive("ngSearch", function(){
function link($scope, element, attrs, ctrl) {
console.log($scope.value);
$scope.$watch("value", function(newValue, oldValue){
console.log(newValue, oldValue);
console.log("value updated");
ctrl.$setViewValue($scope.value);
}, true);
setTimeout(function() {console.log(attrs.value);}, 6000);
}
return {
restrict: 'A',
require: 'ngModel',
scope: {
"value": "#",
},
link: link,
}
})
$(".ui.dropdown").dropdown();
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.2/semantic.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.2/semantic.min.js"></script>
<div ng-app="myApp">
<div ng-conroller="MyController">
<div class="ui fluid multiple search normal selection dropdown">
<input type="hidden" name="country" value="test1" ng-search ng-model="users">
<i class="dropdown icon"></i>
<div class="default text">Select testing</div>
<div class="menu">
<div class="item" data-value="test1">test1</div>
<div class="item" data-value="test2">test2</div>
<div class="item" data-value="test3">test3</div>
</div>
</div>
</div>
</div>
same version in jsfiddle: http://jsfiddle.net/e5aes1fe/1/

Related

Updating ngModel from Custom Directive

I've built a custom directive for generating and populating a dropdown from JSON Data.
However I want to react to a dropdown selection with a function. Therefore I want to make use of ngChange (and ngModel).
So I try to start by updating the ng-model from the directive.
The link function in the Directive should give me everything I need.
BUT the fourth parameter is undefined therefore I can't use it or even compile.
Directive TS:
module lsw{
lswApp.lswAppModule.directive("guiDropdown",
() => ({
restrict: "E",
require: "ngModel",
scope: {
data: "=",
ctrl: "="
},
link(scope, element, attrs, ctrls) {
element.bind("change", () => {
});
},
templateUrl: "../../App_Scripts/Directives/guiDropdown.html"
}));}
"ctrls:{}"
My Idea was to make use of ctrls.$setViewValue to update ngModel
Directive HTML
<div class="elements">
<select name="{{data.name}}" class="dropdown-box">
<option ng-repeat="option in ctrl" ng-value="option">{{option}}</option>
</select>
Main View HTML
<div ng-repeat="element in HomeController.wrapper" ng-if="HomeController.trigger">
<div ng-switch="element.type">
<div ng-switch-when="dropdown">
<gui-dropdown data="element" ctrl="HomeController.content" ng-model="element" ng-change="HomeController.test()"></gui-dropdown>
</div>
<div ng-switch-when="textfield">
<gui-textfield data="element"></gui-textfield>
</div>
<div ng-switch-when="checkbox">
<gui-checkbox data="element"></gui-checkbox>
</div>
</div>
</div>

angularjs template binding

I have developed a transclude directive and I set it to use angularjs template script everything works fine but I still cannot access the bind data.
My code:
index.html
<div side-element="box" title="Links">
<ul>
<li>Link 1</li>
<li>Link 2</li>
</ul>
</div>
<script id="box" type="text/ng-template">
<div class="side-box">
<div class="content">
<h2 class="header">Box {{ title }}</h2>
<span class="content" ng-transclude></span>
</div>
</div>
</script>
<script id="ad" type="text/ng-template">
<div class="side-ad">
<div class="content">
<h2 class="header">AD {{ title }}</h2>
<span class="content" ng-transclude></span>
</div>
</div>
</script>
app.js:
angular.module('myApp.directives')
.directive('sideElement', function ($templateCache, $log) {
return {
scope: {
title: '#'
},
transclude: 'element',
link: function(scope, element, attrs, ctrl, transclude){
var template = $templateCache.get(attrs.sideElement);
var templateElement = angular.element(template);
$log.info(scope.title);//Output the title i put in the html which is (Links)
transclude(scope, function(clone){
element.after(templateElement.append(clone));
});
}
};
});
the scope inside the link function(....) displaies the correct title but it doesn't work in the html:
Box {{ title }}
Link 1
Link 2
I think I missed one thing but I can't figure it out, I need your help to complete the cycle.
Thanx in advance,
The template element that contains the angular binding expressions must be compiled first, and then linked. The compilation phase prepares the template, while the linking phase sets up your $watchers for your binding expressions.
Demo Here
Here is a compile function that should work:
.directive('sideElement', function ($templateCache, $compile, $log) {
return {
restrict: 'A',
transclude: true,
scope:'#',
compile: function(element, attrs) {
var template = $templateCache.get(attrs.sideElement);
var templateElement = angular.element(template);
element.append(templateElement);
return function(scope, element, attr, ctrl, transclude) {
$log.info(scope.title);
}
}
}

Create a list of items built using angularjs

I would like to create a list of items built in Directive and share through controllers.
Here is my example in plunker: Example of my code
Here is my code in js:
var app = angular.module('app', []);
app.controller("BrunchesCtrl", function ($scope, $log) {
$scope.brunches = [];
$scope.addNew = function () {
$scope.brunches.push({ address: "" });
};
$scope.$watch('brunch.address', function(value) {
$scope.address = value;
$log.info($scope.address);
});
$scope.$watch(function() { return $scope.brunches.length; }, function() {
$scope.brunches = $scope.brunches.map(function (brunch) {
return brunch;
});
});
});
app.directive('brunchesView', function ($compile) {
return {
restrict: 'E',
templateUrl: 'brunch.html',
controller: 'BrunchesCtrl',
replace: true,
link: function (scope, element, attrs, controller) {
}
};
});
app.directive('businessSubmit', function ($log, $compile, formManagerService) {
return {
restrict: 'AE',
controller: 'BrunchesCtrl',
link: function (scope, element, attrs, controller) {
formManagerService.init();
var hasError;
element.on('click', function (e) {
e.preventDefault();
$log.info("brunches: \n");
$log.info(scope.brunches);
});
}
};
});
Here is an HTML:
<!DOCTYPE html>
<div class="controls">
<a class="btn btn-danger" id="addBrunch" data-ng-click="addNew()">
<i class="icon-plus-sign"></i>
add new...
</a>
</div>
</div>
<brunches-view class="well" data-ng-repeat="brunch in brunches">{{brunch}}</brunches-view>
<br/>
<p class="well">
JSON: {{brunches | json}}
</p>
<div class="control-group">
<div class="controls">
<a class="btn btn-primary" href="#" data-business-submit>
<i class="icon-save"></i>
Save...
</a>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
<script src="script.js"></script>
And here is the template:
<div class="fc-border-separate">
<div class="control-group">
<label class="control-label">Address</label>
<div class="controls">
<input type="text" class="span6 m-wrap"
name="Address" data-ng-model="address"
value="{{address}}" />
</div>
</div>
</div>
The final thing I want to save the whole data inside the BusinessSubmit directive.
Help please...
Several issues with your code.
First, your ng-model for the <input> is set to address, but the object you are wanting to bind it to a brunch object that has an address property. Important to realize that ng-repeat will create a child scope for every repeated item
<input data-ng-model="brunch.address"/>
Another issue is you are assigning the parent controller to a directive as well. Important to understand that controllers are singletons so if you use controller more than once , each is a separate instance. Therefore nesting the parent controller in a directive makes no sense.
DEMO- [ng-model] fix
If you want the data shared with other controllers you should set up a service that holds the brunches data by injecting it into whatever controllers will need access

angular.js two directives, second one does not execute

I have two directives defined in an angular.js module. The HTML element that is declared first executes its directive, but the second HTML element that uses the other directive does not execute it.
Given this HTML:
<div ng-app="myApp">
<div ng-controller="PlayersCtrl">
<div primary text="{{primaryText}}"/>
<div secondary text="{{secondaryText}}"/>
</div>
</div>
and this angular.js code:
var myApp = angular.module('myApp', []);
function PlayersCtrl($scope) {
$scope.primaryText = "Players";
$scope.secondaryText = "the best player list";
}
myApp.directive('primary', function(){
return {
scope: {
text: '#'
},
template: '<h1>{{text}}</h1>',
link: function(scope, element, attrs){
console.log('primary directive');
}
};
});
myApp.directive('secondary', function(){
return {
scope: {
text: '#'
},
template: '<h3>{{text}}</h3>',
link: function(scope, element, attrs){
console.log('secondary directive');
}
};
});
The resulting HTML is only the "primary" directive, and the "secondary" directive does not render:
<div ng-app="myApp" class="ng-scope">
<div ng-controller="PlayersCtrl" class="ng-scope">
<div primary="" text="Players" class="ng-isolate-scope ng-scope">
<h1 class="ng-binding">Players</h1>
</div>
</div>
</div>
The console output verifies this as well, as only the "primary directive" text is output.
Then if I switch the order of the primary and secondary elements, the secondary directive is executed and the primary directive is not:
<!-- reversed elements -->
<div secondary text="{{secondaryText}}"/>
<div primary text="{{primaryText}}"/>
<!-- renders this HTML (secondary, no primary) -->
<div ng-app="myApp" class="ng-scope">
<div ng-controller="PlayersCtrl" class="ng-scope">
<div secondary="" text="the best player list" class="ng-isolate-scope ng-scope">
<h3 class="ng-binding">the best player list</h3>
</div>
</div>
</div>
Why is this? What am I doing wrong?
div's are not void elements and require a closing tag.
<div ng-app="myApp">
<div ng-controller="PlayersCtrl">
<div primary text="{{primaryText}}"></div>
<div secondary text="{{secondaryText}}"></div>
</div>
</div>
Example

Sending value to nested element in angular

I have the following HTML to make an accordion:
{{isExpandAllOpen}} // Present in the scope of the calling page
<li class="row" ng-repeat="test in AllTests">
<div vh-accordion-group panel-class="panel-info">
<div vh-accordion-header> </div>
<div vh-accordion-body> </div>
</div>
</li>
In vhAccordionHeader.js we have the following code:
home.directive("vhAccordionHeader", ['version', function(version) {
return {
require: '^vhAccordionGroup',
replace: true,
restrict: 'EA',
transclude: 'element',
templateUrl: "JS/HomeModule/Directives/vhAccordion/vhAccordionHeader.html?v=" + version
};
}]);
home.directive("vhAccordionAssignId", function() {
return {
require: '^vhAccordionGroup',
link: function(scope, element, attrs, vhAccordionGroupController) {
scope.isOpen = true;
}
};
});
in AccordionHeader.html
<div class="panel-heading">
<h4 class="panel-title">
<a ng-click="isOpen = !isOpen" data-toggle="collapse" onclick=" return false; " vh-accordion-assign-id>
<i class="pull-left glyphicon" ng-class="{'glyphicon-chevron-up': isOpen, 'glyphicon-chevron-down': !isOpen}" style="margin: -2px 10px 0 0"></i><span ng-transclude></span>
</a>
</h4>
the isOpen variable controls the expand/collapse all functionality.
Since I want to implement a expand/collapse all functionality, using the isExpandAllOpen to be equal to IsOpen, when expanding all button is used.
I cannot find a way to assign isExpandAllOpen to isOpen as it is a diferent directive.
TIA
As you don't specify isolated scope for your vhAccordionAssignId directive you an get access to isExpandAllOpen via scope inheritance. Simply read scope.isExpandAllOpen. Mind that scope inheritance will work for reading only.
Now you want to be notified when it got changed? Put a watcher in your link function
scope.$watch('isExpandAllOpen', function(newVal){
scope.isOpen = newVal;
//do additional stuff if required
});

Categories