split colon in view page using angularjs - javascript

I want replace colon in view page using angularjs.
For example i have some unique data like that
$scope.PlayerList =[{
"ID" : "111:Player",
"Name" : "Rasberry, Jackson (16U Blue)",
"Type" : null
}, {
"ID" : "112:Player",
"Name" : "Keller, Jacob",
"Type" : null
}]//This is my list
Here is my html
<div ng-repeat="item in PlayerList track by $index">
<input type="ceckebox" id="{{item.ID}}">
<!--Real out put is like that <input type="checkbox" id="111:Player"> -->
But i want to like <input type="checkbox" id="111Player">
</div>
I want to omit colon(:) in view page using angularjs without change $scope.layerList properties
If you have any idea please help me.........................

You can create a filter to achieve the results. Update code to following
<input type="ceckebox" id="{{item.ID | customText}}">
.filter('customText', function() {
return function ( input ) {
return input.split(":").join('');
};
})

Related

changing model property value is changing the same property in other object

im new to vue , i want user to be able to add some specific social media links to the page and edit some properties like it's text
i have 2 objects in my data , models and defaults
defaults contains selectable option for social media links and their initial values
basically i copy the default value into models and let the user customize the model via inputs
data () {
return {
models : [] ,
defaults : {
twitter : { id : null , placeholder : 'my twitter' , icon : 'twitter' , text : null , 'link' : null } ,
instagram : { id : null , placeholder : 'my instagram' , icon : 'instagram' , text : null , 'link' : null } ,
tiktok : { id : null , placeholder : 'my tiktok' , icon : 'tiktok' , text : null , 'link' : null } ,
} ,
}
} ,
so there a select menu for user to select which social he wants to add to the page
Select :
<ul >
<li v-for="(social, index ) in defaults" :key="index">
<a #click="appendSocial(index)">
{{ index }}
</a>
</li>
</ul>
here is my #click="appendSocial(index)" function
appendSocial(type){
let typedefault = this.defaults[type];
this.models.push(typedefault)
},
and finally i show my models to user and provide an input for editing it's text via v-model
<div v-for="(model, index) in models" v-bind:key="model.id">
<a class="button-preview">
{{ model.text === null ? model.placeholder : model.text }}
</a>
<label>Text</label>
<input type="text" v-model="model.text" :key="index" :placeholder="model.placeholder">
</div>
so here is the problem , for some reason changing the models properties will change the same property in defaults ... and changing defaults properties will change the same property models !!
like if i add a twitter menu to the page and change it's text (model.text) to abc via v-model ... it will also change defaults.twitter.text to abc
to better demonstrate the problem i've added some console log to my appendSocialfunction
appendSocial(type){
let typedefault = this.defaults[type];
console.log(`-------- default object for ${type} -----------`);
console.log(typedefault);
this.addElement(typedefault);
},
here is the result
1 - i've selected a twitter link and added to my models , you can see defaults.twitter.text is null
2 - i've change my model.text (i suppose it would be models[0].text) to abc
3 - i've added another twitter link to my page ... this time defaults.twitter.text is also abc
also changing defaults properties will effect all the models the has been getting their value from that default object
like if i change the defaults.instagram.text to xyz all my models which have got their initial values from defaults.instagram will also change their text to xyz
it's like they are referencing each other , but i haven't passed the value between 2 objects by reference
im not sure what's happening here and how can i prevent this ?
This is because
let typedefault = this.defaults[type];
this.models.push(typedefault)
Is storing the reference to the object into your this.models array. And so if you mutate the element, you're by default changing the base object. A quick and dirty way of doing a deep clone is the following.
let typedefault = this.defaults[type];
let clonedObj = JSON.parse(JSON.stringify(typedefault));
this.models.push(clonedObj)
Note: Lodash library does have a proper deep clone functionality.
https://www.geeksforgeeks.org/lodash-_-clonedeep-method/

Find linked DOM nodes by path with JsViews

Is there an easy way to find DOM nodes in the property path of the linked JS object?
For exmpale I have some object
<script type="text/javascript">
model = {
companyName : "JS Corporation",
address : "",
staff : [
{
name : "Jack Brown",
position : "SW developer"
},
{
name : "John Dow",
position : "Big Boss"
},
{
name: "Billy Hill",
position : ""
}
]
}
</script>
and template
<!-- TEMPLATE -->
<script type="text/x-jsrender" id='companyTamplate'>
<p>company name <input data-link='companyName'></p>
<p>address <input data-link='address'></p>
<fieldset>
<legend>Staff</legend>
{^{for staff}}
<div class='person'>
<p> name <input data-link='name'> </p>
<p> position <input data-link='position'> </p>
</div>
{{/for}}
</fieldset>
</script>
and link them
$.templates('#companyTamplate').link('#companyView',model);
Then I send my object as JSON to a server and get a validation error like this
{
errors : [
{
"path" : "address",
"error" : "empty string"
},
{
"path" : "staff[2].position",
"error" : "empty string"
}
]
}
I want to highlight the input field for address and postion.
For highlighting the address field i can just navigate to
input[data-link=address]
But when I have an error in some array member it's not so evident.
Workaround is to add in input field an attribute with a full path
<input data-link='position' data-link-path='staff[{{:#index}}].position' >
and then navigate to
input[data-link-path="staff[2].position"]
But it's easy to forget add the additional attribute.
Is there a more simple way to solve this problem?
There is not necessarily a one to one mapping from data node to views or DOM nodes. You could have one to none, or one to many (for example if you had two {^{for staff}} tags in your template).
But if you are able to use knowledge of the template structure, then you can navigate the view hierarchy and use APIs such $.view() view.contents() view.childTags() to get from the data back to a chosen element on which you want to act programmatically.
For example in your sample, the following gets the jQuery object for the "Billy Hill" 'position' input:
$.view().get(true, "array").views[2].contents(true, 'input[data-link="position"]')
If you had two {^{for staff}} blocks and you want to navigate to elements in the second block, you can use childTags() APIs to get to the second one:
$.view().childTags("for")[1].tagCtx.contentView.views[2].contents(true, 'input[data-link="position"]')
which again gets you to the "Billy Hill" 'position input'.
See View Hierarchy, $.view() and the various view object and tag object APIs.

AngularJs - ng-repeat - How can I get the key of an element inside a list?

I have a JSON structure (myTags) like this:
[
{ "tag1" : [{"id" : 1} , {"id" : 2 }] } ,
{ "tag2" : [{"id" : 3} , {"id" : 4 }] }
]
In a ng-repeat block I want to access tag1 and tag2.
I tried using key val like this:
<div ng-repeat ="(key,val) in myTags">
<div class="block">
{{key}}
</div>
</div>
But key is 0 and 1 instead of tag1 and tag2. How can I access them?
As the other answers have mentioned, you have the nesting incorrect here.
Try this:
<div ng-repeat="tag in myTags">
<div ng-repeat="(key, array) in tag">
<div class="block">
{{key}}
{{array}}
</div>
</div>
</div>
http://plnkr.co/edit/IwxeUgVF7SkMp8xRAvH7?p=preview
You want to first output each object, and then loop through each object and separate it's key from the inner array of data.
I think you can loop the properties of the object using a nested ng-repeat like this.
<div ng-repeat="obj in myTags">
<div class="block" ng-repeat="(key, value) in obj">
{{key}}
</div>
</div>
working example: http://codepen.io/mkl/pen/oLYrro
Angular is working as expected. Since myTags is an array, the key will of course be the index of each object. The thing you think of as a key is really just some changing property name, which isn't setup in a particularly helpful way.
I suggest changing your service to return things in a different format. For example, if your myTags were an object instead of an array, your code works fine. Your object ideally looks like this:
myTags = {
"tag1" : [{"id" : 1} , {"id" : 2 }] ,
"tag2" : [{"id" : 3} , {"id" : 4 }]
};
See this demo.
If you are handcuffed to format in your question, you should be pulling data off each object within your array. Michael's answer is a good start for this. Changing your markup to something like this:
<div ng-repeat ="obj in myTags">
<!-- each obj is an object with a single property whose value is an array-->
<div class="block" ng-repeat="(key, value) in obj">
<!-- only one key in the object you provided-->
{{key}}
</div>
</div>
Demo for this alternative

ng-repeat with an if-statement in Angular

I have a website with a huge list of 30 articles. Until now this was like 300 lines of HTML code and with angularjs it is now like 10 lines. But some of these articles are special and so I need to be more specific what to show. Here is the HTML code:
<div id="illustratorcontent" ng-repeat="illustrator in illustrators">
<article id="illustratorcontent{{illustrator.ID}}">
<header>
<h3>{{illustrator.name}}</h3>
</header>
<div class="illustratorcontentext">
<p>This work is copyrighted and owned by {{illustrator.name}}...</p>
<p>Details of the copyright holder: </p>
<ul class="listplacing">
<li>Name: {{illustrator.name}}</li>
<li>Website: {{illustrator.name}}'s website</li>
<li>Website: {{illustrator.name}}'s {{illustrator.website2text}}</li>
</ul>
</div>
</article>
</div>
and the IllustratorController is:
function Illustrator ($scope){
$scope.illustrators = [
{
"ID" : "Ilus1",
"name" : "Ilus1",
"website" : "http://Ilus1page.com/"
},{
"ID" : "Ilus2",
"name" : "Ilus2",
"website" : "http://Ilus2page.com/"
}, ...
{
"ID" : "IlusX",
"name" : "IlusX",
"website" : "http://IlusXpage.com/"
"website2text" : "Twitter IlusX",
"website2url" : "http://twitterilusx.com/"
}
]
}
So my question is how can I show the existing information and leave the li out where no info is given.
So on this line:
<li>Website: {{illustrator.name}}'s {{illustrator.website2text}}</li>
how can I say that this line is just shown when the object parameter is given or not empty. I already looked for some ways. There is something called ng-if and ng-ui but that did not work out for me. Also there is a way to realize it with classes and hiding divs. But actually I would prefer to not generate them. And the website2url/website2text is just an example, there are more values than this.
Similar questions, but mine is a bit more special I believe:
angular ng-repeat with condition
https://stackoverflow.com/questions/28334600/paginating-angular-ng-repeat-with-nested-filtering
Hello create filter for to show the link of not like
<li ng-if="showSecondWebLink(illustrator)">....</li>
create function in your controller
$scope.showSecondWebLink = function(illustrator){
if(illustrator.website2url && illustrator.website2text ){
return true;
}
return false;
}
Just try with:
<li ng-if="illustrator.website2url && illustrator.website2text">...</li>

Adding url and alt attributes dynamically with radio buttons in Angularjs

So I have a group of radio buttons that are built dynamically using a JSON file. The JSON file contains things like url (of an image), alt text, etc...
I have it working pretty well, and can change the value of the img src based on the value of the radio button selected. However, what if I need to access other elements of the json object as well so that I can set the alt text of the image depending on the element selected.
Here is a plunkr of the basic functionality as I have it to this point...
http://plnkr.co/edit/bI4ggTNCPSq3o1Bt6gqg?p=preview
The JSON object looks like so:
{
"header_images" : [
{
"id" : "havoc-header",
"alt" : "Some alt text",
"fname" : "admissions-general-havoc-header.jpg",
"url" : "email-assets/header-images/admissions-general-havoc-header.jpg"
},
{
"id" : "cob-header",
"alt" : "Some more alt text",
"fname" : "cob-banner.jpg",
"url" : "email-assets/header-images/cob-banner.jpg"
},
{
"id" : "css-header",
"alt" : "still some more alt text",
"fname" : "css-banner.jpg",
"url" : "email-assets/header-images/css-banner.jpg"
},
{
"id" : "huns-header",
"alt" : "one more alt-text",
"fname" : "huns-banner.jpg",
"url" : "email-assets/header-images/huns-banner.jpg"
}
]
}
The radio buttons are being built in the view like so:
<label ng-repeat="header in assets.header_images">
<input type="radio" ng-model="assets.headerimage" value="{{header.url}}" id="{{header.id}}" data-alt="{{header.alt}}" />
{{header.url}}
</label>
And my controller looks like this:
function MainCtrl($scope, $http) {
$http.get('js/assets.json').then(function(res){
$scope.assets = res.data;
});
}
So basically when a radio button is clicked, I would like to populate this which is outside of the ng-repeat:
<img src="{{assets.headerimage}}" alt="{{alt}}" />
The src attribute is easy enough. I have that working fine...As you can see when one of the dynamic radio buttons are checked, the value is added to the assets.headerimage binding. But, how would I set the appropriate alt text?
I am sure this is really easy, but I can't get my head around it for some reason. I am relatively new to angularjs, so be gentle :D
in your radio ng-model, you are assigning header.url to the model, so you cant access the alt. but instead if you assign the header to the model you will be able to access the alt.
<label ng-repeat="header in assets.header_images">
<input type="radio" ng-model="assets.headerimage" value="{{header}}" id="{{header.id}}" data-alt="{{header.alt}}" />
</label>
<img ng-src="{{assets.headerimage.url}}" alt="{{assets.headerimage.alt}}"/>
Add ng-change event in the input. Assume the alt is in the parent scope, and then you can use $parent to access alt
<input type="radio" ng-model="assets.headerimage" ng-change="$parent.alt = header.alt" ... >
I'll start with a side-note, you should use ng-src (link) for populating source of an image. This way your browser will not hit 404s after request wrong URLs like /{{assets.headerimage}}.
Now, regarding your question. Assuming your id is unique, you could re-work your JSON to a form similar to this:
{
"header_images" : {
"havoc-header": {
"id" : "havoc-header",
"alt" : "Some alt text",
"fname" : "admissions-general-havoc-header.jpg",
"url" : "email-assets/header-images/admissions-general-havoc-header.jpg"
},
"cob-header": {
"id" : "cob-header",
"alt" : "Some more alt text",
"fname" : "cob-banner.jpg",
"url" : "email-assets/header-images/cob-banner.jpg"
},
"css-header": {
"id" : "css-header",
"alt" : "still some more alt text",
"fname" : "css-banner.jpg",
"url" : "email-assets/header-images/css-banner.jpg"
},
"huns-header": {
"id" : "huns-header",
"alt" : "one more alt-text",
"fname" : "huns-banner.jpg",
"url" : "email-assets/header-images/huns-banner.jpg"
}
}
}
then change value="{{header.url}}" of each of your checkboxes to value="{{header.id}}", and finally populate your image like this:
<img ng-src="{{ assets.header_images[assets.headerimage].url }}"/>
Another way does not require modifying the JSON structure, but it still involves using header.id as your model's value. Simply add a function like this to your scope:
$scope.getChosenHeader = function() {
for(var i=0;i<$scope.header_images.length;i++) {
var h = $scope.header_images[i];
if(h.id === $scope.assets.headerimage) {
return h;
}
}
}
and then populate your image like this:
<img ng-src="{{ getChosenHeader().url }}"/>
This way you can access the whole object instead of just url property. Of course remember to only show your <img/> tag if getChosenHeader().url is not undefined

Categories