Unable to load 2 angularJS components in sharepoint content editor webparts - javascript

I have a requirement where I need to load 2 angular components on the same page.
First I have taken a content editor web part and in the HTML source, I have pasted my angular code where I'm fetching list from SharePoint and then displaying on the page.
My first Custom Editor web part Code:
<div ng-app="myApp" ng-controller="myCtrl">
First Name:
<input type="text" ng-model="firstName">
<br> Last Name:
<input type="text" ng-model="lastName">
<br>
<br> Full Name: {{firstName + " " + lastName}}
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
$scope.firstName = "John";
$scope.lastName = "Doe";
});
</script>
Now, I have taken a new custom editor web part and almost written the same code with just the property name changes, but I'm unable to bind the angular to the second web part.
My second web part code:
<div ng-app="myApp1" ng-controller="myCtrl1"> First Name:
<input type="text" ng-model="firstName1"/>
<br/> Last Name:
<input type="text" ng-model="lastName1"/>
<br/>
<br/> Full Name: {{firstName1 + " " + lastName1}} </div>
<script>
var app = angular.module('myApp1', []);
app.controller('myCtrl1', function($scope) {
$scope.firstName1 = "John";
$scope.lastName1 = "Doe";
});
</script><br/>
Can anyone tell me the mistake I'm doing here?
I was able to load the first component properly.
I need to load 2 components on the same page.

You cannot use 2 ng-app directives on the same page. This is by design.
However, you can use multiple controllers and initialize your angular component using angular.bootstrap method.
Modify your first webpart code as below:
<div id="myApp" ng-controller="myCtrl">
First Name:
<input type="text" ng-model="firstName">
<br> Last Name:
<input type="text" ng-model="lastName">
<br>
<br> Full Name: {{firstName + " " + lastName}}
</div>
<script>
var myfirstAppDivId = document.getElementById('myApp');
angular.bootstrap(myfirstAppDivId, ['myApp']);
var myfirstApp = angular.module('myApp', []);
myfirstApp.controller('myCtrl', function ($scope) {
$scope.firstName = "John";
$scope.lastName = "Doe";
});
</script>
Modify your second webpart code as below:
<div id="myApp1" ng-controller="myCtrl1"> First Name:
<input type="text" ng-model="firstName1"/>
<br/> Last Name:
<input type="text" ng-model="lastName1"/>
<br/>
<br/> Full Name: {{firstName1 + " " + lastName1}} </div>
<script>
var mysecondAppDivId = document.getElementById('myApp1');
angular.bootstrap(mysecondAppDivId, ['myApp1']);
var mysecondApp = angular.module('myApp1', []);
mysecondApp.controller('myCtrl1', function($scope) {
$scope.firstName1 = "John";
$scope.lastName1 = "Doe";
});
</script><br/>

Related

Angular JS collect all input values from a div

I am new to Angular JS, I created a div with input elements and I didn't use ng-model for input boxes.
<div class="row">
<br>
<div class="col-sm-10" id="rankingForm" >
<p ng-repeat=" x in $ctrl.outputProductAttributeValueList">
{{x}} <input type="text" />
</p>
<br>
<button type="submit" ng-click="$ctrl.onRankingFormSubmit()"> SUBMIT</button>
</div>
</div>
When I click on submit button I have to access all input values .Please help me how to do that .. I tried as below.
angular.module("productList")
.component("productList",{
templateUrl : "product-list/product-list.template.html",
controller : ["$http" ,"$scope","$document",function productListController($http,$scope,$document){
var self = this;
self.outputProductAttributeValueList =[ "age", "gender","all"];
self.onRankingFormSubmit = function () {
var queryResult = $document[0].getElementById("rankingForm")
console.log(queryResult);
// HERE queryResult is printing how to proceed further
};
}]
});
Now I want to collect all those input values dynamically created by ng-repeat. Please tell me how to do that ?
AngularJS ngModel is the standard approach for binding the view into the model instead of interacting directly with the DOM.
You can get all the inputs within the div id="rankingForm" you can do:
var inputs = $document[0]
.getElementById('rankingForm')
.getElementsByTagName('input');
Or by using Document.querySelectorAll():
var inputs = $document[0].querySelectorAll('#rankingForm input');
Once you have the inputs than iterate over all of them to get the values.. Notice that I have added attribute name to the inputs:
Code whitout ngModel:
angular
.module('App', [])
.controller('AppController', ['$scope', '$document', function ($scope, $document) {
$scope.outputProductAttributeValueList = ['age', 'gender', 'all'];
$scope.onRankingFormSubmit = function () {
var inputs = $document[0].querySelectorAll('#rankingForm input');
inputs.forEach(function(input) {
console.log(input.name + ': ' + input.value);
});
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
<div ng-app="App" ng-controller="AppController" class="row">
<br>
<div class="col-sm-10" id="rankingForm" >
<p ng-repeat="x in outputProductAttributeValueList">
{{x}} <input type="text" name="{{x}}" />
</p>
<br>
<button type="submit" ng-click="onRankingFormSubmit()">SUBMIT</button>
</div>
</div>
Code with ngModel:
angular
.module('App', [])
.controller('AppController', ['$scope', '$document', function ($scope, $document) {
$scope.outputProductAttributeValueList = ['age', 'gender', 'all'];
// Model inputs
$scope.inputs = {};
$scope.onRankingFormSubmit = function () {
$scope.outputProductAttributeValueList.forEach(function(input) {
// Access to model inputs: $scope.inputs[input]
console.log(input + ': ' + $scope.inputs[input]);
});
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.9/angular.min.js"></script>
<div ng-app="App" ng-controller="AppController" class="row">
<br>
<div class="col-sm-10" id="rankingForm" >
<p ng-repeat="x in outputProductAttributeValueList">
{{x}} <input type="text" ng-model="inputs[x]" />
</p>
<br>
<button type="submit" ng-click="onRankingFormSubmit()">SUBMIT</button>
</div>
</div>

AngularJS the scope value does not display in the views

I am a newbie in angularjs; the scope value are not displaying in the views.
I have two apps: myApp and ram - each one having their controllers.
I'm trying to display scope values.
Only myApp shows values but ram does not.
<div ng-app="myApp" ng-controller="myCtrl">
First Name: <input type="text" ng-model="firstName"><br>
Last Name: <input type="text" ng-model="lastName"><br>
<br>
Full Name: {{firstName + " " + lastName}}
</div>
<div ng-app="ram" ng-controller="myCtrl2">
First Name: <input type="text" ng-model="firstName2"><br>
Last Name: <input type="text" ng-model="lastName2"><br>
<br>
Full Name: {{firstName2 + " " + lastName2}}
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.firstName= "John";
$scope.lastName= "Doe";
});
</script>
<script>
var app2 = angular.module('ram', []);
app2.controller('myCtrl2', function($scope) {
$scope.firstName2= "ram";
$scope.lastName2= "babu";
});
</script>
You have to bootstrap modules to have multiple ng-app in your page.
<html>
<head>
<script src="angular.min.js"></script>
</head>
<body>
<div id="App1" ng-app="shoppingCart" ng-controller="ShoppingCartController">
<h1>Your order</h1>
<div ng-repeat="item in items">
<span>{{item.product_name}}</span>
<span>{{item.price | currency}}</span>
<button ng-click="remove($index);">Remove</button>
</div>
</div>
<div id="App2" ng-app="namesList" ng-controller="NamesController">
<h1>List of Names</h1>
<div ng-repeat="_name in names">
<p>{{_name.username}}</p>
</div>
</div>
<script>
var shoppingCartModule = angular.module("shoppingCart", [])
shoppingCartModule.controller("ShoppingCartController",
function($scope) {
$scope.items = [
{product_name: "Product 1", price: 50},
{product_name: "Product 2", price: 20},
{product_name: "Product 3", price: 180}
];
$scope.remove = function(index) {
$scope.items.splice(index, 1);
}
}
);
var namesModule = angular.module("namesList", [])
namesModule.controller("NamesController",
function($scope) {
$scope.names = [
{username: "Nitin"},
{username: "Mukesh"}
];
}
);
angular.bootstrap(document.getElementById("App2"),['namesList']);
</script>
</body>
</html>
You can not use two apps on the same page. If you do that then you will need to use Angular Bootstrap.
First assign your second div an id e.g id ="ramID" to something like below
<div id="ramID" ng-app="ram" ng-controller="myCtrl2">
then add this line to your code to your script
angular.bootstrap(document.getElementById("ramID"),['ram']);
hope it helps.

How to validate a form in a directive from the view

I want my button enable when both forms are valid.
My button is in the view at the level of the controller while a form is in a directive. What I have done does not work. I thought there might be some wrong syntax within my ng-disabled="" on my button. How do I accomplish this issue without some weird hack? Sorry, I'm new to Angularjs.
Here are my codes.
Cheers!!
index.html
<div ng-app="myApp" ng-controller="myCtrl">
<myform user="user1"></myform>
<myform user="user2"></myform>
<button ng-disabled="user1.formname.$invalid || user2.formname.$invalid">My Button</button>
</div>
my script
var app = angular.module('myApp', []);
app.controller('formCtrl', function($scope) {
$scope.user1 = {formname: "user1form" ,firstName: "John", lastName: "Doe"};
$scope.user2 = {formname: "user2form" ,firstName: "Lisa", lastName: "Smith"}
});
app.directive( 'datepickerform', function() {
return {
restrict: 'E',
scope: {
user : '='
},
templateUrl: 'myform.html',
link: function( scope, element, attrs ) {}
};
});
myform Directive Template :
<form name="user.formname" novalidate>
First Name:<br>
<input type="text" ng-model="user.firstName" required><br>
Last Name:<br>
<input type="text" ng-model="user.lastName" required>
</form>

combined properties in expression angularjs

I have a controller with contact object in his scope.
If the contact has first name or last name, I want to show first-name<space>last-name.
My problem is that when the contact has no first name or last name. In this situation I want to show the user Create new contact but because there is a space between the first name and last name in the expression, it displays only the spacing.
Start typing in the inputs and you will that, basically, both of divs should show the same.
angular.module('myApp', []).
controller('ctrl', function($scope) {
//$scope.contact = {
// FirstName: 'first',
// LastName: 'last'
//}
$scope.contact = {};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="myApp" data-ng-controller="ctrl">
<input type="text" data-ng-model="contact.FirstName" placeholder="first name" />
<input type="text" data-ng-model="contact.LastName" placeholder="last name" />
<hr />
<!-- If I add space between first and last name it will never show 'Create new conttact' -->
{{contact.FirstName + ' ' + contact.LastName || 'Create new contact'}}<br />
{{contact.FirstName + contact.LastName || 'Create new contact'}}
</div>
You can use ng-if to fix your issue.
I have updated the code to match your requirements. Hope this helps.
angular.module('myApp', []).
controller('ctrl', function($scope) {
//$scope.contact = {
// FirstName: 'first',
// LastName: 'last'
//}
$scope.contact = {};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="myApp" data-ng-controller="ctrl">
<input type="text" data-ng-model="contact.FirstName" placeholder="first name" />
<input type="text" data-ng-model="contact.LastName" placeholder="last name" />
<hr />
<!-- If I add space between first and last name it will never show 'Create new conttact' -->
{{contact.FirstName + ' ' + contact.LastName}}
<span ng-if="(contact.FirstName == null || contact.FirstName == '') && (contact.LastName == null || contact.LastName == '')">Create New Contact</span>
</div>
There can be many ways this can be achieved. But since you want to achieve this in expressions only it can be done as below.. Just use the trim() in the expression.
Second solution:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div data-ng-app="myApp" data-ng-controller="ctrl">
<input type="text" data-ng-model="contact.FirstName" placeholder="first name" />
<input type="text" data-ng-model="contact.LastName" placeholder="last name" />
<hr />
<!-- If I add space between first and last name it will never show 'Create new conttact' -->
{{(contact.FirstName + ' ' + contact.LastName).trim() || 'Create New Contact'}}
</div>
If I understand your question correctly you can just use ng-show/ng-hide:
<div data-ng-app="myApp" data-ng-controller="ctrl">
<span ng-show="contact.FirstName && contact.LastName">
{{contact.FirstName + ' ' + contact.LastName}}
</span>
<span ng-hide="contact.FirstName && contact.LastName">
Create new contact
</span>
</div>
Is that what you were looking for?
You here have 2 options 1 create a function that return true or false if you have first or last name or do the verification into html:
Solution 1:
angular.module('myApp', []).
controller('ctrl', function($scope) {
$scope.contact = {};
$scope.verifyContacts = function(){
return contact.FirstName || contact.LastName;
}
});
<div data-ng-app="myApp" data-ng-controller="ctrl">
<span ng-hide="verifyContacts()">Create new contact</span>
<span ng-show="verifyContacts()">{{contact.FirstName + ' ' + contact.LastName}}</span>
</div>
Soution 2:
This soution will invole to write the expresion form the verifyContacts function from above solution inline so your html will look like:
<div data-ng-app="myApp" data-ng-controller="ctrl">
<span ng-hide="contact.FirstName || contact.LastName">Create new contact</span>
<span ng-show="contact.FirstName || contact.LastName">{{contact.FirstName + ' ' + contact.LastName}}</span>
</div>
I personally prefer the first solution.
Edit: presenting the third solution:P
Solution 3:
You can add a space at the end of the first name if the first name is available so you don't need to concat the strings with space
angular.module('myApp', []).
controller('ctrl', function($scope) {
$scope.contact = {};
contact.FirstName = contact.FirstName ? contact.FirstName + ' ' : contact.FirstName;
}
});
<div> {{contact.FirstName + contact.LastName || 'Create new contact'}} </div>
this will work but as you can see in your code that the input fields are not displayed so you most probably will need a back-end function for that or something.

AngularJS: Creating Query Form for Database

So I am having a little problem creating a very simple query form due to my lack of understanding about coding. As you can see in the app.js below, I have FormController, which retrieves information from the form, feeds it into the jsonUrlGen function which creates a custom URL, which is then sent to my SolrController which accesses that URL and pulls the JSON information from it.
However it is quite clear after taking a step back and looking at it that the structure of my code is wrong, and I am missing an app.service to link the shared variables between my two controllers. I'm also not even sure if I need two controllers in this instance, but it just happened as I was coding it.
If anybody can tell me what I'm doing wrong here I would really appreciate it, because the code just flat out does not work.
Thanks.
.HTML FILE
<html ng-app="solrApp">
<head>
<link link rel="stylesheet" href="bootstrap-3.3.5-dist/css/bootstrap.min.css" />
<link link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/1.4.3/angular.min.js"></script>
<script type= "text/javascript" src="app.js"></script>
</head>
<body>
<!--<h1 class="headline">Logo or Something Here</h1>-->
<div class="logo"><img src="images/CubedE.png" id="cubedE"/></div>
<div class = "queryForm" ng-controller="FormController">
<input type="text" class="queryBox" id="mainQueryString" placeholder="Query String" ng-model="fullQuery.queryString"><br />
<input type="text" class="queryBox" placeholder="Filter Query" ng-model="fullQuery.filterQuery"><br />
<input type="text" class="queryBox" placeholder="Sort By" ng-model="fullQuery.sortBy"><br />
<h2>Extract only from rows:</h2>
<input type="text" class="halfQueryBox" placeholder="Start" ng-model="fullQuery.startRow"><input type="text" class="halfQueryBox" placeholder="End" ng-model="fullQuery.endRow"><br />
<input type="text" class="queryBox" placeholder="Field List (Separate by comma)" ng-model="fullQuery.fieldList"><br />
<input type="text" class="queryBox" placeholder="Raw Query Parameters (key1=val1&key2=val2)" ng-model="fullQuery.rawQuery"><br />
<button type="button" ng-click="jsonUrlGen()">Submit Query</button>
</div>
<div class = "results" ng-controller="SolrController">
<ul>
<li ng-repeat="item in items">
{{ item.key }} - <em>{{ item.value }}</em>
</li>
</ul>
</div>
</body>
</html>
APP.JS
(function(){
var app = angular.module('solrApp', []);
app.controller('FormController', function($scope) {
$scope.fullQuery = {
queryString: '',
filterQuery: '',
sortBy: '',
startRow: '',
endRow: '',
fieldList: '',
rawQuery: ''
}
$scope.jsonUrlGen = function(){
var jsonURL = "http://localhost:8983/solr/core/select?";
if($scope.fullQuery.queryString !== '') {
jsonURL = jsonURL + "q=" + $scope.fullQuery.queryString;
}
else if($scope.fullQuery.filterQuery !== '') {
jsonURL = jsonURL + "&fq=" + $scope.fullQuery.filterQuery;
}
else if($scope.fullQuery.sortBy !== '') {
jsonURL = jsonURL + "&sort=" + $scope.fullQuery.sortBy;
}
else if($scope.fullQuery.startRow !== '') {
jsonURL = jsonURL + "&start=" + $scope.fullQuery.startRow;
}
else if($scope.fullQuery.endRow !== '') {
jsonURL = jsonURL + "&rows=" + $scope.fullQuery.endRow;
}
else if($scope.fullQuery.fieldList !== '') {
jsonURL = jsonURL + "&fl=" + $scope.fullQuery.fieldList;
}
else {
return "exception thrown";
}
jsonURL = jsonURL + "wt=json";
return jsonURL;
};
});
app.controller('SolrController', function($scope, $http){
$http.get($scope.jsonUrlGen)
.then(function(res){
$scope.items = res.data;
});
});
})();
Answers may be opinionated since there are multiple ways to accomplish this.
I would advise to restructure html. Have a single controller that wraps the "form" and the contents of SolrController. Also the "form" should really become a <form>. In angular there is a default controller created for this tag and it helps a lot with managing validation and handling submit.
<div class="results" ng-controller="SolrController">
<form class="queryForm" name="queryForm" ng-submit="submit()">
<input type="text" class="queryBox" id="mainQueryString" placeholder="Query String" ng-model="fullQuery.queryString"><br />
<input type="text" class="queryBox" placeholder="Filter Query" ng-model="fullQuery.filterQuery"><br />
<input type="text" class="queryBox" placeholder="Sort By" ng-model="fullQuery.sortBy"><br />
<h2>Extract only from rows:</h2>
<input type="text" class="halfQueryBox" placeholder="Start" ng-model="fullQuery.startRow"><input type="text" class="halfQueryBox" placeholder="End" ng-model="fullQuery.endRow"><br />
<input type="text" class="queryBox" placeholder="Field List (Separate by comma)" ng-model="fullQuery.fieldList"><br />
<input type="text" class="queryBox" placeholder="Raw Query Parameters (key1=val1&key2=val2)" ng-model="fullQuery.rawQuery"><br />
<button ng-disabled="queryForm.$invalid">Submit Query</button>
</form>
<ul>
<li ng-repeat="item in items">
{{ item.key }} - <em>{{ item.value }}</em>
</li>
</ul>
</div>
Mind name attribute for the form. It will help to access the form in the scope. Actually when there is a name angular creates $scope.queryForm in parent controller
By default all buttons (and <input type="submit") on form submit on click. But type="button" will prevent it. So remove it
Controller SolrController. It's inappropriate to perform a request before user had a change to input something. $http.get should work on a click handler which we choose to be submit event.
app.controller('SolrController', function($scope, $http){
$scope.fullQuery = {};//ng-model will take care of creating all properties
function jsonUrlGen(){ //same code here
}
$scope.submit = function(){
$http.get(jsonUrlGen())
.then(function(res){
$scope.items = res.data;
});
});
};
})
Hope this helps

Categories